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获取后直接返回,而不用回到最外层函数域。避免了全局变量,同时优化了递归运算。
- 即日起珠海可用微信乘公交,腾讯乘车码助力智慧城市建设
- 利用mk-table-checksum监测Mysql主从数据一致性操作记录
- mysql主从同步(4)-Slave延迟状态监控
- 浏览器窗口尺寸改变时的图片自动重新定位
- Mongodb主从复制/ 副本集/分片集群介绍
- Paul-Adrien Menez:互联网与抵制食物浪费的故事
- DRBD详细解说及配置过程记录
- Servant:基于Web的IIS管理工具
- Web前端知识体系精简——CSS 篇
- 几种异步操作方式
- 今天的面试小记
- objective-C中的序列化(serialize)与反序列化(deserialize)
- 微信小程序 template 模板功能实现循环
- ASP.NET Web API 接口执行时间监控
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 面试官问我Volatile的原理?从操作系统层面的设计怼回去!
- 设计原则之单一职责
- 设计原则之开闭原则
- SpringBoot执行跨域处理
- SpringBoot对全局异常的处理封装
- 自定义springboot-starter揭秘自动配置骚操作
- 【大厂面试题】Redis中是如何实现分布式锁的?
- 最近公司招人,研发组商量了下,暂时定下这么多java面试题!
- 市面上数据库种类那么多,如何选择?
- 玩转正则!推荐一个速查、调试、验证、可视化工具
- 当一个http请求来临时,SpringMVC究竟偷偷帮你做了什么?
- Js实现文本复制
- 当一个http请求来临时,SpringMVC究竟偷偷帮你做了什么?处理器映射器与处理器篇
- anetTcpGenericConnect 详解
- 详解 MySQL 基准测试和sysbench工具