JS两个特性
JS有两个特性,一个是单线程,一个是解释性语言。不同于编译性语言,解释性语言通常理解为不整体编译,由解释器解释一句执行一句。但JS不是直接对着代码解释执行,在解释执行之前,需要进行其他的步骤。
imply global 暗示全局变量
- 即任何变量,如果变量未经声明就赋值,此变量就为全局对象所有。
- 在游览器环境下一切声明的全局变量,全部是window的属性
var a = 123 === window.a =123
函数作用域中的预编译(AO对象)
介绍
AO对象全称为:activation object (活跃对象/执行期上下文),在函数执行前执行函数预编译,此时会产生一个AO对象,AO对象保存该函数的参数变量。
执行四步骤
- 创建
AO对象( activation object )即 活跃对象 - 找到形参和变量声明,将变量和形参作为
AO对象的属性名,值为undefined - 将实参值和形参统一
- 在函数里面声明的函数,函数名作为AO对象的属性名,值赋值给函数体。(若参数名和函数名重叠,则函数体值会覆盖参数值)
代码演示
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)
代码分析
第一步 创建AO对象,就是执行期上下文
AO {}
第二步 找到形参和变量声明,将变量和形参最为AO对象的属性名,值为undefined
AO {
a: undefined // 这里形参名和变量名有相同的话只需要写一个
b: undefined
}
第三步 将实参值和形参统一
AO {
a: 1
b: undefined
}
第四步 在函数体里面找函数声明,值赋予函数体
AO {
a: function a() {}
b: function() {}
d: function d() {}
}
结果
所以接下来我们再看fn函数整体
function fn(a) {
console.log(a) // function a() {}, 在AO对象中获取
var a = 123
console.log(a) // 123
function a() {}
console.log(a) // 123
var b = function (){}
console.log(b) // function() {}
function d() {}
}
fn(1)
全局作用域中的预编译(GO对象)
介绍
GO对象全称为 global object(全局对象,等同于window),在开始预编译时产生的对象,比AO对象先产生,用于存放全局变量,也称为全局作用域。
预编译三步骤
- 创建
GO对象,这里的GO对象===window对象 - 将变量声明的变量名当做GO对象的属性名,值为undefinded
- 将声明函数的函数名当做GO对象的属性名,值为函数体
代码演示
var a;
console.log(a)
function test1(a, b) {
var a;
console.log(a)
a = 4;
function test2() {
a = 5;
var b = 123;
function a() {};
console.log(a)
}
return test2()
}
console.log(a)
var b = 'this B';
console.log(b)
test1('this A', 'this b')
代码分析
1. 生成GO对象
GO {}
2. 将声明变量添加进GO对象内,值为undefined
GO {
a: undefined
b: undefined
}
3. 将声明函数添加进GO对象呢,值为函数体
GO {
a: undefined
b: undefined
test1: function test1() {...}
}
4. 预编译完成,执行代码:输出两个a,此时a的值为:undefined, 输出b,此时b的值为:this B ,
5. 执行 test1() 函数,生成 AO 对象
test1 AO {}
6. 将 test1() 声明的变量添加到AO对象,值为undefined
test1 AO {
a: undefined
b: undefined
}
7. 将 test1() 函数中的形参和实参相统一
test1 AO {
a: this A
b: this b
}
此处变量a并没有使用关键字,所以变量a会存放在全局作用域中,全局声明了var a; 赋值4
8. 将 test1() 函数中找函数声明的函数名当做AO对象的属性名,值为函数体
test1 AO {
a: this A
b: this b
test2: function test2() {...}
}
9. 执行 test2() 函数,生成 AO 对象
test2 AO {
b: undefined
}
此处变量a并没有使用关键字,所以变量a会存放在全局作用域中,全局声明了var a; 赋值4 => 5
10. test2() 函数没有形参和实参跳过
11. 将 test2() 函数中找函数声明的函数名当做AO对象的属性名,值为函数体
test2 AO {
b: undefined
a: 5
}
结果
var a;
console.log(a) // undefined
function test1(a, b) {
var a;
console.log(a) // this A
a = 4;
function test2() {
a = 5;
var b = 123;
function a() {};
console.log(a) // 5
}
return test2()
}
console.log(a) // undefined
var b = 'this B';
console.log(b) // this B
test1('this A', 'this b')