初看这段代码感觉不太能理解,如果按照词法作用域来看,bar函数所在的词法作用域为foo,那么在定义时,是没有i这个变量的,那么i = 3 应该是找到window上的。
但是其实词法作用域只是指的当函数在运行时,函数所在的作用域是在那个位置,而不是运行时,去找函数定义时作用域所处的状态。
也就是说foo函数在运行到for循环时,已经在foo这个作用域上增加了 i 这个变量,这样运行bar这个函数时,在bar这个函数词法作用域foo中,由于存在了i这个变量,当bar函数中给i赋值,相当于给foo这个作用域上的i赋值。
我们可以思考如下这段代码
function bar (a) {
i = 3;
}
function foo () {
for (var i = 0; i < 10; i++) {
console.log(i)
bar(i * 2)
}
}
foo()
console.log(i)
这个时候bar的词法作用域在全局上了,所以当设置 i = 3时,改变的并不是foo作用域中的i,而是会在LHS寻址上找不到i变量,并在全局上创建一个i变量。
所以在ES5 中使用let来定义,可以让i变量只存在于for循环这个块级作用域中,当然我这里表述可能不太正确,但差不多就是这个意思,参考如下代码
function foo () {
function bar (a) {
i = 3;
}
for (let i = 0; i < 10; i++) {
console.log(i)
bar(i * 2)
}
}
foo()
console.log(i)
其实对于作用域或者函数来说,主要作用其实就是封装和复用吧。让变量在比较多的情况下不至于污染全局,少很多重复代码,如果没有函数的话其实代码也能写,只是没有现在这么优雅而已
网友评论