一、闭包的概念
函数套函数,子级函数外面用了父级函数的变量,这种状况就属于闭包。
函数套函数作用只是为了造出一个局部变量。
二、作用域的概念
假如一段代码被保留在独自的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。