例子:
(1) var a = 10;
console.log(a); -->结果 10
(2) a = 10;
console.log(a); -->结果 10
(3) console.log(a); -->报错,提示说a未定义
var a = b = 3;
在JS中执行顺序为从右到左,因此首先会执行b = 3【此语句说明b为全局变量,归window所有】,而此时b属于未定义状态,因为var 只针对a,该语句的含义是将3赋值给变量b,然后再声明a,将b的值赋给a.
但是如果执行
console.log(window.a);-->undefined
console.log(window.b);-->3
说明变量未经声明就被赋值,该变量归window所有
重点:
(1)变量未经声明就赋值,则属于window
(2)一切声明的全局变量,均是window的属性
例如在JS初始化时,var a = 23;则window.a-->23;
1.3.1 案例一
function fn(a){
console.log(a); ②
var a = 123; ③
console.log(a); ④
function a(){}; ⑤
console.log(a); ⑥
var b = function(){}; ⑦
console.log(b); ⑧
function d(){}; ⑨
}
fn(1);
执行函数前一刻会进行预编译操作
讲解:
(1)创建AO【Activation Object】对象,简称为执行期上下文
(2)找出形参和变量声明,并将变量和形参名作为AO对象的属性,值为undefined
(3)将形参和实参进行统一,即将实参传递的值赋给形参名
(4)在函数体里找函数声明,并将值赋予函数体
程序讲解:
根据预编译的执行时间来说,预编译一般都发生在程序执行前一刻,因此该预编译的执行:
(1) 首先会创建一个AO对象
AO{
}
(2) 根据预编译的四部曲
在程序中找出形参和所有的变量声明,并将形参名和变量名作为属性存放到AO对象中,形参为fn(a)中的a,变量声明有:var a;var b;
并且属性名的值为undefined
注意:此处的形参为a,变量名也存在a,但在AO对象中存放时,如有相同的名称,那仅放一次即可。
因此AO对象为:AO{
a : undefined,
b : undefined
}
(3) 实参和形参进行统一,即将实参的值赋给形参
形参为a,实参为1,
因此AO对象为:AO{
a : 1,
b : undefined
}
(4) 查找函数声明,并将函数体赋值给属性
函数声明以function 开头,因此程序中的函数声明有:a,d两种。但由于AO对象中已存在属性a,[a原先的值被新的值所替代]
因此AO对象为:AO{
a : function a(){},
b : undefined,
d: function d(){}
}
上述过程均属于预编译,以下开始执行程序中的语句
(1) 首先执行语句②
将a的值打印,a的值会从预编译所产生的AO对象中去获取
所以语句console.log(a); 执行的结果为:function a(){}
(2) 执行语句③
由于变量的声明提升,var a在预编译时就被执行,所以现在只执行a = 123的语句,AO对象变为:
AO{
a : 123,
b : undefined,
d: function d(){}
}
语句④的执行结果为123
(3) 执行语句⑤
function a(){};属于函数声明,而根据函数声明提升,在预编译时就被执行,所以该语句不再执行
(4) 执行语句⑥
打印a的值,依然会去AO对象中获取值,结果为:123
(5) 执行语句⑦
var b = function(){};
这属于函数表达式,而var b根据变量声明提升,在预编译时已被执行,所以直接将b的值放入到AO对象中
AO{
a : 123,
b : function(){},
d: function d(){}
}
(6) 执行语句⑧
从AO对象中获取b的值:function(){}
(7) 执行语句 ⑨
function d(){};属于函数声明,根据函数声明提升,该语句在预编译时已执行,所以不再执行
最终的AO对象为:
AO{
a : 123,
b : function(){},
d: function d(){}
}
1.3.2 案例二
function test(a,b){
console.log(a);
c = 0;
var c;
a = 3;
b = 2;
console.log(b);
function b(){};
function d(){};
console.log(b);
}
test(1);
一、预编译开始
1、创建AO对象
AO{
}
2、找到形参和变量声明,并将形参名和变量名作为AO对象的属性
并赋值为undefined
AO{
a:undefined,
b:undefined,
c:undefined
}
3、将实参同形参进行统一
AO{
a:1,
b:undefined,
c:undefined
}
4、查找函数声明,并将函数体赋给属性
AO{
a:1,
b:function b(){},
c:undefined,
d:function d(){}
}
预编译完成。
二、开始执行程序
(1) console.log(a);
执行后,会从预编译中创建的对象AO获取值:即a = 1;
(2) c = 0;
AO{
a:1,
b:function b(){},
c:0,
d:function d(){}
}
(2) var c;
变量声明提升,不再执行
(3) a = 3;
AO{
a:3,
b:function b(){},
c:0,
d:function d(){}
}
(4) b = 2;
AO{
a:3,
b:2,
c:0,
d:function d(){}
}
(5) console.log(b);
执行结果为:2
(6) function b(){};
函数声明提升,不再执行
(7) function d(){};
函数声明提升,不再执行
(8) console.log(b);
执行结果为:2
1.3.3 案例三
全局对象window
在预编译中,除了存在AO对象,同时也有GO对象,所谓GO即为
Global Object === window 这是同一个对象的不同名称而已。
function test(){
var a = b = 123;
}
AO{
a : undefined
}
GO{
b : 123
}
GO对象的构成同AO的步骤一样,除了实参和形参进行统一的步骤没有,其他步骤均存在。
1.3.4 案例四
全局对象复杂案例
console.log(test);
function test(test){
console.log(test);
var test = 234;
console.log(test);
function test(){
}
}
test(1);
var test = 123;
程序讲解:
一、预编译
1、创建GO对象
GO对象>AO对象
2、GO对象的构成,会针对于script中所有的程序而言,不会同AO创建时,仅仅针对于函数内部,因此在全局范围类查找形参和变量声明
GO{
test : undefined
}
3、找到函数声明,并赋值函数体
GO{
test : undefined
}
4、找函数声明,因此全局对象为:
GO{
test : function test(){}
}
预编译完成,开始执行程序
二、程序执行
(1) console.log(test);
执行结果会从GO对象中获取值,结果为
function test(test){
console.log(test);
var test = 234;
console.log(test);
function test(){
}
}
(2) test(1);//去调用以下函数
function test(test){
console.log(test);
var test = 234;
console.log(test);
function test(){
}
}
执行该程序时,会创建AO对象
AO{
}
根据AO对象的预编译四部曲
a、查找形参和变量声明,并将形参名和变量名作为属性,值为
undefined
AO{
test : undefined
}
b、将实参和形参进行统一
AO{
test : 1
}
c、查找函数声明,并赋值函数体
AO{
test : function test(){}
}
编译完成,内部程序执行
a、console.log(test); //function test(){}
b、var test = 234;
AO{
test : 234
}
c、console.log(test);//234
d、function test(){};//预编译已执行,不再执行
因此最终的AO对象为
AO{
test : 234
}
(3) var test = 123;
全局对象为:
GO{
test : 123
}