JS预编译
JS有两个特性,一个是单线程,一个是解释性语言。不同于编译性语言,解释性语言通常理解为不整体编译,由解释器解释一句执行一句。但JS不是直接对着代码解释执行,在解释执行之前,需要进行其他的步骤。
JS运行步骤:
预编译有个特点:任何变量,如果未声明就赋值,那该变量为全局变量,即暗示全局变量(imply global)。并且所有的全局变量都是window的属性。
function fn(){
var a = b =123;
}
test();
解析:这是一个连续赋值的过程,赋值是从右向左赋值,先把123赋给b,再把b赋给a,其实导致b未经声明就赋值了,所以这个b属于window的属性。
AO对象
AO对象全称为:activation object (活跃对象/执行期上下文),在函数执行前执行函数预编译,此时会产生一个AO对象,AO对象保存该函数的参数变量。
函数预编译步骤
- 创建AO对象
- 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
- 将实参的值赋值给形参。
- 在函数体里面找函数声明,函数名作为AO对象的属性名,值赋值给函数体。(若参数名和函数名重叠,则函数体值会覆盖参数值)
实战分析
function test(a) {
console.log(a);//function a(){}
var a = 2;
console.log(a);//2
function a () {
}
console.log(a);//2
var b = function () {
};
console.log(b);//function () {}
function d(){
}
}
test(1);
</script>
test函数执行过程分析:
1、创建AO对象
AO {
}
2、找AO对象的属性名
AO{
a:undefined
b:undefined
}
3、将实参值赋值给形参
AO{
a:1
b:undefined
}
4、处理函数里面的声明函数
AO{
a:function a () {
} //变量名一样,值覆盖
b:undefined;
d:function d () {
};
}
此时函数预编译已经完成的,预编译后执行代码:
第一条执行的是控制台打印出a的值,所以输出function a () {};
第二条语句赋值给a,则AO对象中a的值被覆盖为2;
AO{
a:2
b:undefined;
d:function d () {
};
}
第三条语句控制台打印a的值为2;
第四条为声明,预编译处理过所以直接跳过;
第五条打印出a的值,一样为2;
第六条为赋值,赋值b的值为function () {};
AO{
a:2
b:function () {
};
d:function d () {
};
}
第七条打印出b的值function () {};
第八条声明,预编译处理过所以直接跳过;
GO对象
GO对象全称为 global object(全局对象,等同于window),在开始预编译时产生的对象,比AO对象先产生,用于存放全局变量,也称为全局作用域。
预编译三步骤
- 生成GO对象
- 将变量声明的变量名当做GO对象的属性名,值为undefinded
- 将声明函数的函数名当做GO对象的属性名,值为函数体
实战分析
function test(){
console.log(b);//undefined
if(a){
var b = 100;
}
c =234
console.log(c);//234
}
var a ;
test();
a =10;
console.log(c);//234
实战分析:
1、创建GO对象
GO{
}
2、将声明变量添加进GO对象内,值为undefined
GO{
a:undefined;
}
3、将声明函数添加进GO对象呢,值为函数体
GO{
a:undefined;
function test() {
… };
}
预编译完成,执行代码
第一条 控制台输出a,此时a的值为:undefined
第二条 a赋值,此时GO对象内的a值变为100
GO{
a:100;
function test() {
… };
}
第三条 执行函数test(),生成AO对象
AO{
}
第四条 将函数声明的变量添加进AO对象,值为undefined
AO{
a:undefined;
}
(函数没有传递参数,跳过函数预编译的第三步)
(函数里面没有声明函数,跳过函数预编译的第四步)
第五条 执行函数,打印a,此时AO里面有属性a,则输出AO里面a的值,即输出: undefined
第六条 AO的a赋值200,此时AO的a的值为200
AO{
a:200;
}
第七条 输出a的值:200
第八条 将300的值赋值给b再赋值给a,此时b未声明,所以b为全局变量,将b添加进GO对象内,将a的值改为300
GO{
a:100;
function test() {
… };
b:300;
}
AO{
a:300;
}
第九条 输出a的值:300,函数执行完成
第十条 输出b的值:300
第十一条 输出a的值,此时a的值为GO里面的值:100
几道面试题
function test(){
console.log(b);//undefined
if(a){
var b =100;
}
console.log(b);//undefined
c =234;
console.log(c);//234
}
var a ;
test();
function bar(){
return foo;
function foo(){
}
var foo =11;
}
console.log(bar());
console.log(bar());
function bar(){
foo=10;
function foo(){
}
var foo=11;
return foo;
}
var x = 1;
if( function f(){
} ){
x += typeof f;
// console.log(f);
}
console.log(x);
// if的()将function f(){}变为一个表达式,是立即执行函数,执行结束后就销毁
// 所以x += typeof f; 中,f此时是无定义,若直接console.log(f)会报错:ReferenceError: f is not defined
// typeof(f)是唯一一种不报错并返回字符串"undefind",所以x为字符串"1undefined"