一、作用域
1. 全局作用域
写脚本块中的代码
全局作用于中声明的变量,会被提前到代码块的顶部进行定义,成为全局对象的属性
2. 函数作用域
函数内部定义的变量,会被提升到函数代码块中的顶部,并且不会成为全局对象的属性
1.全局作用域
代码如下(示例):
console.log(a);//undefined 声明一个空间 并赋默认值 undefined
var a = 10;
console.log(a);//10
console.log(window.a);// 作用域上找不到会报错;原型链上找不到显示undefined
2.函数作用域(局部作用域)
代码如下(示例):
function test(){
var a = 10;
console.log(a);//10
}
test();
console.log(a);//报错(a is not defined)
function demo(){
var a = 10;
b = 20;// 直接赋值未声明会变成全局变量,会造成全局污染
console.log(a,b);// 10 20
}
demo();
console.log(b); // 20
console.log(a); // 报错
function fn(){
// var x = y = 20; //这一行代码可以拆分为下面两行代码
var x = y;// 代码执行到这一行会报错,不会有任何输出(y is not defined)
y = 20;
console.log(x);
console.log(y);
}
fn();
console.log(y);
console.log(x);
function fn(){
var x = y;
var y = 20;
console.log(x); //undefined
console.log(y); //20
}
fn();
console.log(y); //报错
console.log(x);
函数内部定义的变量,会被提升到函数代码块中的顶部
下边是上面函数执行的解析:
function fn(){
var x; //提前声明
var y; //提前声明
x = y; //因为此时y只定义了未赋值,所以把默认值undefined赋给x
y = 20; //把20赋给y
console.log(x); //undefined
console.log(y); //20
}
fn();
二、预编译
简单来说预编译就是变量和函数的提前声明
js代码执行三部曲:
1.语法检测
2.预编译
3.代码执行
1.全局预编译
- 创建一个GO对象 Global Object
- 将var关键字声明的变量当作GO对象的属性,赋值为undefined,有重名的直接覆盖
- 将function关键字声明函数 当作GO对象的属性,值为函数体,重名直接覆盖
2.函数预编译
函数在执行的前一刻开始会经历以下过程:
- 创建一个AO对象 Activation Object 执行期上下文对象
- 函数的形参,成为AO对象的属性,值为实参的值,若未传值,值为undefined
- 将var关键字声明的变量,成为AO对象的属性,值为undefined,遇到已经存在的,不做任何变化
- 将function声明的函数 成为AO对象的属性 值为函数体,重名直接覆盖
3.代码举例
例1:
console.log(a);//undefined
var a = 10;
console.log(a);// 10
console.log(test); // function test(){console.log('Roddy');}
test(); //Roddy
function test(){
console.log('Roddy');
}
test(); //Roddy
解析:
GO{
a:undefined
test:function test(){
console.log("Roddy");
}
// 代码执行到a=10
f:10
}
例2:
function ld(){
console.log(1); // 3
}
f();
function ld(){
console.log(2); // 3
}
f();
function ld(){
console.log(3);// 3
}
ld();
var ld = 100;
console.log(ld); // 100
解析:
GO{
ld:undefined
// 声明结束后
ld:function ld(){
console.log(3);// 3
}
// 代码执行到ld=100,ld函数体再次被覆盖
f:100
}
三、作用域链
- 万物皆对象,函数也是一个对象
- function test(){}
- test.name test.prototype
- 函数中隐式的属性 test.[[scope]]
- [[scope]] : 指的就是我们所说的作用域,就是存储运行期的执期上下文集合。
- 作用域链 : [[scope]] 中存储的执行器上下文对象的集合,这个集合呈现链式链接,我们把这种链式链接叫做作用域链。
- 执行期上下文对象:当函数执行时,创建一个执行期上下文,定义了函数执行时的环境,函数每次执行时,执行期上下文都是独一无二的,所以每调用一次函数都会创建一个独立的执行期上下文,当函数执行完毕时,它所产生的执行期上下文会被销毁。
例1:
function outLuodi(){
function inLuodi(){
var b = 666;
}
var a = 999;
inFun();
}
var glob = 520;
outFun();
解析:
GO:{
glob:undefined,
outLuodi:function,
glob:520
}
outLuodi函数在定义时
outLuodi.[[scope]] 0:GO存入到[[scope]]中
outLuodi函数在调用时创建一个AO对象
AO{
a:999
inLuodi:function
}
outLuodi.[[scope]] 0:AO
1:GO存入到[[scope]]中
inLuodi函数定义时
inLuodi.[[scope]] 0:outLuodi AO
1:GO存入到[[scope]]中
inLuodi函数调用时创建一个AO对象
AO{
b:666
}
inLuodi.[[scope]] 0:inLuodi AO
1:outLuodi AO
2:GO存入到[[scope]]中
outLuodi被定义时
outLuodi被执行时
inLuodi被定义时
inLuodi被执行时