书接上回,今天我们继续细聊js的执行机制
var&let
按照惯例,我们先来看段代码:
ini
var arr = []
for (var i = 0; i < 10; i++) {
arr[i] = function() {
console.log(i);
}
}
for (var j = 0; j < arr.length; j++) {
arr[j]()
}
问:这段代码的输出是啥?
我们直接看结果:
震惊,为啥是十个10?
我们来进行分析
在for
循环语句中,第一次循环是i=0;i<10成立,执行
scss
arr[i] = function() {
console.log(i);
}
然后i++,一直到i为9,i<10成立,执行
scss
arr[i] = function() {
console.log(i);
}
i++,此时i为10,i<10不成立,结束循环,开始调用arr[j]()
这个时候其实arr
相当于
lua
arr = [
function () {
console.log(i);
},
function () {
console.log(i);
},
function () {
console.log(i);
},//...从0-9有10次function()
]
当我们去看这个arr
里的i
时,function()
里并没有定义它,只能去作用域链的下一级找i
,也就是全局。这时候for
循环已经在全局声明了10个函数体,且此时i
为10,这样就输出了十个10.
那我们怎么把这段代码改成输出的是0-9呢?
我们思考一下,打印出十个10的根本原因就是function()
作用域链的下一级是全局,如果我们让for
循环形成作用域,function()
就不算做声明在全局了,i就不会去全局里找。
让for形成作用域只用改一个小点,咱们把for里的var i = 0
改为let i = 0
即可, 这里们了解var
和let
的概念就很好理解 :
-
var
:声明的变量具有函数作用域或全局作用域,也就是说同一个函数或全局范围内,var
声明的变量可以在任何地方被访问和修改。 -
let
:能够提供块级作用域,即let
声明的变量只能在包含它的代码块(例如for
循环)内被访问和修改。
OK,知道了这个知识点之后我们运行验证一下:
结果符合
闭包
概念
在JavaScript中,根据词法作用域的规则,内部函数可以访问定义它的作用域中的变量,当内部函数被拿到外部函数之外调用时,即使外部函数已经执行完毕,但是内部函数对外部函数中的变量依然存在引用,那么这些被引用的变量会以一个集合的方式保存下来,这个集合就叫做闭包。当然在这个闭包中outer指针也依旧会被保留下来。
我个人会把闭包理解为飞机上的黑匣子,机毁盒存
作用
实现变量私有化
优缺点
优点
- 记忆功能:闭包可以记住它被创建时的信息,这在编程中非常有用,因为它可以帮助我们保存数据,而不需要每次都重新设置。
- 数据保护:闭包可以保护数据不被外部直接访问。
缺点
- 占用空间:闭包如果保存了太多数据,会占用计算机的内存。
- 意外行为:在编程中,如果不正确地使用闭包,可能会导致一些意外的行为。
- 速度变慢:如果程序中使用了很多闭包,可能会让程序运行得慢一些。
例子说明
看下面这段代码:
php
function foo() {
function bar() {
var age = 18
console.log(myName);
}
var myName = 'Tom'
return bar
}
var myName = 'Jerry'
var fn = foo()
fn()
分析
第一步 创建全局的执行上下文:
第二步 运行到给fn
赋值,发现调用了foo()
,导致foo的执行上下文入栈,并调用foo()
,foo()
中的return
导致fn
变为一个函数体
js
第三步 此时foo()执行完毕,出栈销毁。fn()调用,fn()此时为bar(),即bar的执行上下文入栈
bar()
中有myName
的输出,但是bar()
里找不到myName
的声明,只能去下一级作用域链里找,但是此时的foo()
执行上下文对象已被销毁,按理来说应该会报错,但是结果却是正常运行:
结合概念
为什么,我们的分析哪里出问题了?foo
函数的执行上下文不是被销毁了吗?
确实被销毁了,但是闭包 的存在,bar
函数仍然可以访问到foo
函数作用域中的变量。
当foo
函数执行时,它返回了bar
函数的一个引用。这个返回的bar
函数形成了一个闭包,它能够访问创建时的作用域链,即使foo
函数的执行上下文已经结束。这是因为闭包保留了对创建时作用域的引用。
结语
以上就是本文全部内容,通过今天的学习,我们了解了JavaScript中var
与let
的区别,以及闭包的概念和应用。希望能对读者理解js的执行机制有所帮助,感谢阅读!