zoukankan      html  css  js  c++  java
  • js变量提升的一个小坑

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

    对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),页面还在开发当中,希望能得到各位的指点 ^_^

  • 相关阅读:
    SVN服务器搭建和配置使用详解
    Oracle命令大全
    mysql史上最全的学习资料
    jquery性能优化的38个建议
    vijosP1037搭建双塔
    vijosP1159 岳麓山上打水
    vijosP1038 添加括号
    BZOJP1003 [ZJOI2006]物流运输trans
    vijosP1006 晴天小猪历险记之Hill
    洛谷1043 数字游戏
  • 原文地址:https://www.cnblogs.com/iny7/p/5398101.html
Copyright © 2011-2022 走看看