专栏首页前端架构与工程JavaScript递归中的作用域问题

JavaScript递归中的作用域问题

需求是这样的,从子节点寻找指定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,一开始我试图用如下递归获取:

 1 function getNode(){
 2     var child = $("#layer_4");
 3     var parent = getParent(child);
 4     return parent;
 5 }
 6 
 7 function getParent(el){
 8     var result;
       result = el.parentNode;
 9     if(!el || el === document.documentElement || el.parentNode   === document.documentElement){
10         return;
11     }else if(result && result.className === "layer_1"){
12         return result;
13     }else{        
14         getParent(result);
15     }
16     return result;
17 }
18 
19 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获取后直接返回,而不用回到最外层函数域。避免了全局变量,同时优化了递归运算。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【译】《Understanding ECMAScript6》- 第八章-Module

    目录 模块是什么 使用基础 接口标识符重命名 缺省接口 Re-exporting 非绑定import 总结 JavaScript令人困惑并且易引发错误的特性之一...

    寒月十八
  • 浅谈事件冒泡

    前端开发中不可避免会接触到事件冒泡,今天简单记录一下处理事件冒泡的一点经验,谈不上心得,聊当抛砖引玉。 不谈移动端,以PC浏览器的click事件为例。 事件冒泡...

    寒月十八
  • Github page搭建博客使用自定义插件的方法

    Github page的后台程序是由Jekyll搭建,但由于Github的保护措施,非认证的plugin一般不会被Github page支持,但可以使用一些小技...

    寒月十八
  • python列表与元组的用法

    7.列表生成式   #[i*i for i in range(10)]       [i*i for i in range(10) if i>5]

    py3study
  • 2015.11.30 HTML5真题练习

    HTML5学堂:每天一道题,强壮程序员!今日主要涉及昨日题目的解答,以及一道涉及函数的形参实参、arguments对象的题目 HTML5真题【2015.11.2...

    HTML5学堂
  • Leetcode: Reverse Bits

    题目: Reverse bits of a given 32 bits unsigned integer.

    卡尔曼和玻尔兹曼谁曼
  • Nmap NSE 缺陷

    可以看到,我在 portrule 处直接返回了 true ,所以按照规则来说,无论端口是什么规则,都会执行,但是结果如下

    意大利的猫
  • 写一个 golang 风格的协程扩展

    Kotlin 的协程库 kotlinx.coroutines 当中有个比较常用的 async 函数,返回的 Deferred<T> 有个 await 方法,这个...

    bennyhuo
  • Typo3 CVE-2019-12747 反序列化漏洞分析

    TYPO3是一个以PHP编写、采用GNU通用公共许可证的自由、开源的内容管理系统。

    Seebug漏洞平台
  • Typo3 CVE-2019-12747 反序列化漏洞分析

    TYPO3是一个以PHP编写、采用GNU通用公共许可证的自由、开源的内容管理系统。

    知道创宇云安全

扫码关注云+社区

领取腾讯云代金券