码迷,mamicode.com
首页 > Web开发 > 详细

js变量提升的一个小坑

时间:2016-04-16 13:47:34      阅读:203      评论:0      收藏:0      [点我收藏+]

标签:

好久没写博客了,原本想实训结束能对整个实训项目认真总结一下,没想到回到学校一点都不轻松,最近在制作网页版简历,遇到了一个小问题,现在不总结以后肯定忙得顾不上,所以长话短说,抓紧时间写下来.

对js语法比较熟的同学可能都知道:js是没有块级作用域的,有一个新手很容易出错的地方

for(var i = 0 ; i < 10 ; i ++){
    setTimeout(function(){
        console.log(i)
    },1000*i)
}

这段代码会输出10个10,而不是期望的1,2,...,10,原因正是因为每次循环的作用域是相同的,于是他们共享同一个i,这个问题很简单,这里就不细说了,这次要说的在后面

注意下面这段代码


console.log(a)  // undefined
if(!a){
    var a = 1;
}
console.log(a)  //1

倘若a不存在,就声明一个变量a并复制为1,这段代码运行起来,控制台会不出意外地打印出 1 , 看起来好像没什么问题, 但实际发生了什么呢?

1. 将该作用域中使用的所有变量提升到当前作用域的首部进行声明,对于这段代码,因为js没有块级作用域,相当于将代码改为

var a;
/*其他变量*/

2. 声明完毕后执行代码

if(!a){  //执行到这里时a其实已经声明了,只是没有赋值
    a = 1;
}
console.log(a);  //1
/*其他语句*/

看起来好像不是什么太大的问题,但是在某些情况下对这件事情不理解就麻烦啦,举个例子,在遍历树的时候我们要用到递归,就拿递归来说事吧

function test(){
    console.log("test");
    if(!a){
        var a = 1;
    }
    if(a < 3){
     a++; test(); } }

在外部调用test会发生什么呢? 至少我在写这篇博客以前以为会输出3个test了事,事实是,函数不断地调用自身,无休止地打印test

在开发中写这样一段函数时,我的想法是:在递归的入口函数保存一个数组,函数执行的过程中会根据条件进入不同的分支,从而在这个数组中增或删一些元素,最终将该数组返回,实际运行时发现返回的结果并不符合预期,每一次调用好像都重新声明了一个数组, if(!a) 的判断根本没有向调用者(父作用域)中查找变量,抓耳挠腮了很久,才突然想起以前看过变量提升相关的总结.只是因为当时觉得这个事情在其他语言里也会发生,很简单,就没当回事,果然今天就受到了制裁,耽误了不少时间才想到这里

其实理解这个问题很简单,写下面一段代码测试

if(!a){  //a尚未声明
    a = 1;
}
console.log(a) //报错Uncaught ReferenceError: a is not defined

因为没有使用var关键字,js引擎没有对a进行变量提升,所以在运行到第一行的时候a是未声明的变量,会直接报错

那么怎么test()到底怎么写呢?

var path;
function find(orignNode, desNode){
    if(!path){
console.log(
"初始化路径") path = [orignNode]; }
   temp = /*其他代码*/;
find(orignNode, temp);
}

目前我是这么解决的,很明显的缺点:占用了父作用域中的变量path,并且每次调用find前都要对path置空,这样的代码看起来很不爽,但是迫于水平有限,一时也没有想出更好的办法(还有一个方法是绑定到当前函数所处的闭包中(this.path),函数return之前

var path = this.path;
delete this.path;
return path;

感觉也没好到哪里去,若您有好的解决方案,欢迎在下面留言

另外,打个小广告,也是我发现这个问题的源头,就是我的个人主页啦(http://iny7.com),页面还在开发当中,希望能得到各位的指点 ^_^

 

js变量提升的一个小坑

标签:

原文地址:http://www.cnblogs.com/iny7/p/5398101.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!