需求是这样的,从子节点寻找指定className的父节点,一开始就想到递归(笨!),Dom结构如下:

<div class="layer_1">
<div class="layer_2">
<div class="layer_3">
<div id="layer_4"></div>
</div>
</div>
</div>

先通过id获得layer_4的div,然后逐层向上寻找最外层的layer_1,一开始我试图用如下递归获取:

 function getNode(){
var child = $("#layer_4");
var parent = getParent(child);
return parent;
} function getParent(el){
var result;
result = el.parentNode;
if(!el || el === document.documentElement || el.parentNode === document.documentElement){
return;
}else if(result && result.className === "layer_1"){
return result;
}else{
getParent(result);
}
return result;
} getNode(); //undefined

结果返回的是undefined!

本来是一最基本的递归,为什么会出现这种结果?

其实修改这个问题很简单,目前我只想到一个办法:将result声明为全局变量!

当然这个方法的缺点是造成了memory leak,折中的解决办法是在获取到result后将result =null。

可能有朋友看到这里就已经知道这个问题的原因了,那就是:JavaScript中function的作用域问题-闭包!下面详细解释一下。

如果按照上面的写法,

1、每次递归调用getParent()方法是都会声明一个局部变量result,同时因为闭包的缘故,每次的gerParent()的运行作用域又保留着上次getParent()的作用域,所以每次都会覆盖上层同名的result,作为一个当前函数域的局部变量;

2、当找到layer_1后,result更新,return result得到了我们想要的结果,跳出本次函数域,进入上层函数域,但此时的上层函数域中result并未更新(因为被下层函数域的同名result屏蔽了),所以此时最外层的result仍然是undefined!

所以最终将的到undefined!

这个问题同样引出了以前遇到的关于return的bug,当时把return想象的太强大了,以为return会跳出整条作用域链,上述问题证明了return只能跳出当前作用域,以后注意!

补充:谢谢亮哥的指导,用全局变量解决确实是最笨的法子了,以下是改进办法:

function getParent(el){
var result;
result = el.parentNode;
if(!el || el === document.documentElement || el.parentNode === document.documentElement){
return;
}else if(result && result.className === "layer_1"){
return result;
}else{
return getParent(result);
}
}

在每次递归调用时用return跳出当前函数域,之后进入下层函数时result获取后直接返回,而不用回到最外层函数域。避免了全局变量,同时优化了递归运算。

JavaScript递归中的作用域问题的更多相关文章

  1. 【授课录屏】JavaScript高级(IIFE、js中的作用域、闭包、回调函数和递归等)、MySQL入门(单表查询和多表联查)、React(hooks、json-server等) 【可以收藏】

    一.JavaScript授课视频(适合有JS基础的) 1.IIFE 2.js中的作用域 3.闭包 4.表达式形式函数 5.回调函数和递归 资源地址:链接:https://pan.baidu.com/s ...

  2. JavaScript中的作用域

    很多(JavaScript)开发者都在讨论"作用域",但它是什么?它们在JavaScript中的任何地方!我发现很多年轻的开发者不知道作用域是什么.他们中大多数人可以用jQuery ...

  3. 浅谈javascript中的作用域

    首先说明一下:Js中的作用域不同于其他语言的作用域,要特别注意     JS中作用域的概念: 表示变量或函数起作用的区域,指代了它们在什么样的上下文中执行,亦即上下文执行环境.Javascript的作 ...

  4. 【翻译】JavaScript中的作用域和声明提前

    原文:http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html ===翻译开始=== 你知道下面的JavaScript脚本执 ...

  5. JavaScript中的作用域和声明提前

    [翻译]JavaScript中的作用域和声明提前 原文:http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html ===翻译 ...

  6. 认识javascript中的作用域和上下文

    javascript中的作用域(scope)和上下文(context)是这门语言的独到之处,这部分归功于他们带来的灵活性.每个函数有不同的变量上下文和作用域.这些概念是javascript中一些强大的 ...

  7. javascript学习中自己对作用域和作用域链理解

    在javascript学习中作用域和作用域链还是相对难理解些,下面我关于javascript作用域和作用域链做一下详细介绍,给各位初学者答疑解惑. 首先我们介绍一下什么是作用域?  从字面上理解就是起 ...

  8. 漫谈JavaScript中的作用域(scope)

    什么是作用域 程序的执行,离不开作用域,也必须在作用域中才能将代码正确的执行. 所以作用域到底是什么,通俗的说,可以这样理解:作用域就是定义变量的位置,是变量和函数的可访问范围,控制着变量和函数的可见 ...

  9. 深入理解JavaScript中的作用域和上下文

    介绍 JavaScript中有一个被称为作用域(Scope)的特性.虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,我会尽我所能用最简单的方式来解释作用域.理解作用域将使你的代码脱颖而出,减 ...

随机推荐

  1. linux端口详解大全

    0|无效端口,通常用于分析操作系统 1|传输控制协议端口服务多路开关选择器 2|管理实用程序 3|压缩进程 5|远程作业登录 7|回显 9|丢弃 11|在线用户 13|时间 17|每日引用 18|消息 ...

  2. H5新特性---Web Worker---Web Stroage

    今天的目标 3.1:h5新特性八--Web Worker---代码就3行 程序:program 存储在外存(磁盘)中代码 进程:Process/Task 将程序调用内存中,分配空间 线程:Thread ...

  3. 2019.03.09 bzoj5371: [Pkusc2018]星际穿越(主席树)

    传送门 题意简述: 给一个序列,对于第iii个位置,它跟[limi,i−1][lim_i,i-1][limi​,i−1]这些位置都存在一条长度为111的无向边. 称dist(u,v)dist(u,v) ...

  4. ADO.NET MSSSQLServer 操作简要总结

    1).数据库操作首先应该是链接,链接的方式有多种,不论怎样实现最终都是把链接字符串赋值给实现了 继承自DbConnection 类的SqlConnection类实例的ConnectionString属 ...

  5. mysql实现多实例

    > mariadb安装    yum install mariadb-server > 创建相关目录,及设置权限    mkdir /mysqldb; mkdir /mysqldb/{33 ...

  6. IO模型的介绍

    Stevens 在文章中的一种IO Model: ****blocking IO    #阻塞 IO   (系统调用不返回结果并让当前线程一直阻塞,只有当该系统调用获得结果或者超时出错才返回) *** ...

  7. Connect To Ubuntu 16.04 / 17.10 / 18.04 Desktop Via Remote Desktop Connection (RDP) With Xrdp

    [1] https://websiteforstudents.com/connect-to-ubuntu-16-04-17-10-18-04-desktop-via-remote-desktop-co ...

  8. tcp/ip 三次握手和4次挥手

    TCP连接两个端口,谁也发起请求,谁就是client端A,另外一个接受请求的server端B.第一次握手:A向B发一个链接请求,带一个seq = x,SYN= x. 第二次握手:B收到链接请求之后向A ...

  9. 调用接口,发送https请求

    调用https接口有两种方式 一:是导入证书; 证书调用https请求本人还不知道,希望看见此博客的大神给我回复. 二:是创建信任管理器. 第一步:实现X509TrustManager接口,里面的方法 ...

  10. docker 2(local registry)

    1.获取仓库镜像 ,sudo docker pull registry 2.sudo vim /etc/init/docker.conf 增加--insecure-registry IP:5000 3 ...