乐趣区

关于javascript:JavaScript的作用域链和闭包

一、闭包的概念

函数套函数,子级函数外面用了父级函数的变量,这种状况就属于闭包。
函数套函数作用只是为了造出一个局部变量。

二、作用域的概念

假如一段代码被保留在独自的 js 文件中,当某个蕴含该 js 文件的网页运行在浏览器中的时候,JavaScript 曾经事后创立好一个全局作用域,该作用域蕴含一个全局上下文,该上下文蕴含 window、navigator 等内置的全局对象。

如下代码,当执行到第 3 行并赋值 a = 1 时,全局上下文(全局变量)就蕴含了 ”a” 这个变量,接下来的语句就能应用该变量。当执行到第 4 行时函数 ”fun1″ 也被加到全局上下文中。

// 应用闭包技术的 JavaScript 函数
    // 函数一:var a = 0;
    function fun1() {
        var a = 1;
        function sum(b) {return a+b;}
        return sum(0);
    }
    var c1 = fun1(0);
    // 函数二(匿名函数):var a = 0;
    var c2 = (function(b){
        var a = 1;
        function sum(b) {return a+b;}
        return sum(b);
    })(0);
    console.log(c1,c2); // 1  1

在“fun1”函数中,同样会有一个属于“fun1”的上下文,该上下文同时也会指向全局上下文,同理到函数“sum”外部时,执行环境也会为它建设上下文,同时也会指向它的父上下文。

当第 11 行调用 fun1 函数时,在 sum 函数外部执行环境查看以后的上下文,查找有无变量“a”,当然在此例中没找到,于是他会在父上下文中查找,很显著父上下文 fun1 中有“a”, 所以 a =1,如果 fun1 中没有“a”,会持续向上在全局作用域链中查找。

整个变量查找的过程讲完了。

接下来说一下 ” 函数二 ” 比“函数一”好的中央,fun1 间接裸露在全局上下文中,这样看起来很不妥,万一不小心把这个函数被笼罩了怎么办,很可能会导致命名抵触问题,像函数二那样应用匿名函数间接调用,这样这个函数就不会净化到全局空间。

到这里,大家是否了解了下面所述的作用域的一些概念,接下来看上面一道例题。

三、例题练习

1 for (var i = 0; i < 6; i++) {2     setTimeout(() => {3         console.log(i);
4     })
5 }

请问上述代码打印出的后果是是啥?

后果打印出 6 个 6。
起因是:打印 i 的时候在 setTimeout 函数上下文没有找到 i 变量,一级一级往上找,在父级上下文(for 循环上下文)里找到 i,此时因为异步执行这时的 i 曾经变成了 6,故打印出 6.

那么如何批改该函数使得打印出的后果是 0——5 呢?

// 计划一:for (var i = 0; i < 6; i++) {setTimeout((i) => {console.log(i)
        },400,i)
    }
    // 计划二:for (var i = 0; i < 6; i++) {(function(i){setTimeout(() => {console.log(i)
            },400)
        })(i);
    }

计划一:既然 setTimeout 上下文中没有 i,那么就通过 setTimeout 函数的第三个参数将 i 传进去,使得在 setTimeout 外部上下文中能够找到 i。

计划二:应用 闭包 将 i 传到匿名函数中,setTimeout 通过父级上下文(匿名函数)中找到传进来的 i。

退出移动版