看了很多的javascript 感触良多,javascript的语法与c语言 c++完全不同。javascript的类(es6)也只是function的另一个表示法(语法糖)。本质上javascript的类就是function。
本文章主要是记录一下如何理解作用域。
如果想详细了解请参照How do JavaScript closures work
我只是把其中文章中没有列举的一下问题简要提一下
作用于中用var声明
别的不多说 该文章中的例子
function buildList(list) {
var result = [];
for (let i = 0; i < list.length; i++) {
let item = 'item' + i;
result.push( function() { console.log(item + ' ' + list[i])} );
}
return result;
}
function testList() {
var array=[1,2,3]
var fnlist = buildList(array);
// Using j only to help prevent confusion -- could use i.
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
testList() //logs "item2 undefined" 3 times
结果为
item2 undefined
item2 undefined
item2 undefined
为什么会这样,原因在于testList()运行的时候产生了一个testlist作用域,在这个作用域中有两个本地变量array 和运行buildList(array)。而buildList(array)运行的同时也会产生一个buildList作用域,本来运行buildList之后如果没有外部引用存在的话,垃圾回收机制会回收这部分内存空间。但是我们发现buildlist返回result是
[
function() { console.log(item + ' ' + list[i])} ,
function() { console.log(item + ' ' + list[i])} ,
function() { console.log(item + ' ' + list[i])} ,
]
其中的item 和list[i]均引用了buldList的作用域变量。所以垃圾回收机制不会销毁它。而是保留他。直到作用于消失。
在buildList中声明了的
var result=[]
var i //虽然声明在for里但它是属于buildLIST作用域的
var item //虽然声明在for里但它是属于buildLIST作用域的
当程序运行的时候for循环了三次
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + i;
result.push( function() { console.log(item + ' ' + list[i])} );
}
return result;
每一次循环就会i都会加1 item都会重新赋值 三次循环后i=3,item=“item2”(因为i++的值为3的时候i < list.length为假,不会再循环了);
所以所有的result里的function里 i定位到了3 item 定位到了“item2”,result返回后任然引用了buildList作用于
var result=[function() { console.log(item + ' ' + list[i])},
function() { console.log(item + ' ' + list[i])},
function() { console.log(item + ' ' + list[i])}
]
var i=3 //虽然声明在for里但它是属于buildLIST作用域的
var item="item2" //虽然声明在for里但它是属于buildLIST作用域的
现在返回到testList作用域当中。现在的fnlist就等于
[
function() { console.log(item + ' ' + list[i])},
function() { console.log(item + ' ' + list[i])},
function() { console.log(item + ' ' + list[i])}
]
并且并且item ,i 指向buildLIST的作用域
下一步 for (var j = 0; j < fnlist.length; j++) { fnlistj; }执行 fnlistj,就会执行function() { console.log(item + ’ ’ + list[i])} 并且均指向了buildLIST作用域的值。
分析还没有结束 接着看
作用于中用let 声明
let声明与var不同,var的作用于不会局限在for循环语句和{ }里但是let会局限,也就是let在for循环,在{ }里存在的话在他们外面是访问不到的,这就会让上面的例子有所不同
把i用let来定义
function buildList(list) {
var result = [];
for (let i = 0; i < list.length; i++) {
var item = 'item' + i;
result.push( function() { console.log(item + ' ' + list[i])} );
}
return result;
}
function testList() {
var array=[1,2,3]
var fnlist = buildList(array);
// Using j only to help prevent confusion -- could use i.
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
testList() //logs "item2 undefined" 3 times
返回值为
item2 1
item2 2
item2 3
把 item 和 i 用let 定义
function buildList(list) {
let result = [];
for (let i = 0; i < list.length; i++) {
var item = 'item' + i;
result.push( function() { console.log(item + ' ' + list[i])} );
}
return result;
}
function testList() {
var array=[1,2,3]
var fnlist = buildList(array);
// Using j only to help prevent confusion -- could use i.
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
testList() //logs "item2 undefined" 3 times
结果为
item0 1
item1 2
item2 3
这又是什么原因呢?
这个还是作用域的问题,当在for循环中,每一次循环 i和item 都会被销毁,因为他们不是引用类型(如果是引用类型会怎么样呢,自己猜吧)所以每循环一次 function() { console.log(item + ’ ’ + list[i])} 里的值都会被固定,然后被销毁并在下一次从新赋值。{也可以理解为item和i没有被销毁,只是每次for循环都指向新的值,所以每次的item里的值都不一样(不知道是否正确)} 最终导致结果是这样的。