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

  • 相关阅读:
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31
    知也atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31无涯 - I
  • 原文地址:https://www.cnblogs.com/iny7/p/5398101.html
Copyright © 2011-2022 走看看