1. 函数的内容
var data = [];
for (var i = 0; i < 3; i++) {
data[i] = function () {
console.log(i);
};
}
data[0]();
data[1]();
data[2]();
这里在预解析的过程中会有data[i]变量的声明,且会伴随一个地址。地址的内容不会进行解析,当做字符串处理,当且仅当调用函数的时候才会解析函数内容。所以这里的动作为:
- for循环把
i
增加为3
console.log(i)
在调用函数之前不会运行,且一直保持原样- 运行
data[0]
并执行函数,内容为console.log(i)
,因为i=3
,所以控制台输出3
。后面同理。故最后输出三个3
2.隐式声明
function fn() {
console.log(a)
var a = 5;
function a() {}
console.log(a)
function b() {}
b = 6
console.log(b)
var c = d = b
}
fn()
console.log(d)
console.log(c)
声明变量有很多方法,其中常用的就是用var定义变量,或者用function声明函数,再或者就是用隐式定义。
- 在执行
fn()
之前是没有任何关于abcd
的声明的 fn()
里面,声明了一个a
,声明了a
的地址,声明了b
和b
的地址,声明了c
,
隐式声明了d (这里的隐式声明是全局声明)- 由于在全局里面没有声明c,所以最后两项为
未定义d
和c=6
,故最后全部输出为undefined,5,6,d is not defined,6
- 只有在函数内部才有隐式声明
函数地址与函数
function a(b) {
alert(b);
function b() {
alert(b);
}
b();
}
a(c);
function c() {
return 123;
}
在预解析的时候,每一个声明的函数变量都会伴随一个函数地址,这个地址是指向函数的地址,比如例子中的,function b()
的地址就是function b(){alert (b);}
,而后面的a(c)
中的c
不是c
函数,而是c
的地址,上面的b
同理。
- 预解析,
a
变量及其地址,c
变量及其地址 - 执行,
a(c)
,找到a变量和其地址,带入参数c
,执行a
函数 - 在a函数中,预解析,b变量及其地址。(此时本来是c地址的a(c)变成了a(b))
- 在a函数中,执行,
alert(b)
,b
有定义且有地址,内容为其地址的那串字符串。故弹出function b(){alert(b);}
- 下面同理。故弹出俩
function b(){alert(b);}
声明的先后顺序
function foo(){
function bar() {
return 3;
}
return bar();
function bar() {
return 8;
}
}
alert(foo());
在这个例子里面很容认为第一个return bar()
的值为3,实际上却为8。
涉及到变量声明的先后顺序问题,后声明的同名变量会在预解析的时候覆盖先前的变量声明,但是仅限相同部分(这里的相同部分指的声明,而非函数的具体内容,其他不同部分包括但不限于地址)。
- 全局声明变量
foo()
,且有地址。 - 执行
alert(foo())
- 在
foo
函数内,声明变量bar
及其地址,再声明变量bar
及其地址。后面的bar
将100%覆盖前面的bar
(其优先级为值>地址>声明) - 故
return bar()
触发的是第二个bar
,即return 8