1 背景
最近在学习JavaScript,今天学到了下面的内容,做个回顾吧。
JavaScript递归、预编译
2 学习内容
2.1 JavaScript是解释性语言,执行三部曲如下所示
首先,js对代码进行语法分析,查看有无低级语法错误
然后,进行预编译
最后,解释执行,即解释一行执行一行
2.2 通用规律
函数声明整体提升,变量声明提升
2.2.1 imply global暗示全局变量,即任何变量b,如果变量b未经声明就赋值,此变量就为全局对象所有,全局对象即为window.b可以在函数体外使用
例如:
1 | function test() { |
2.2.2 一切在全局范围内声明的全局变量,全是window的属性
例如:
1 | var a = 1; |
就相当于
1 | window.a = 1; |
2.3 预编译
四部曲:
- 创建AO对象(即Activation Object,执行期上下文)
- 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
- 将实参值和形参统一
- 在函数体里面找函数声明,值赋予函数体
例子1:
1 | function fn(a) { |
上面代码的预编译及执行过程如下
2.3.1.1 创建AO对象
AO {
}
2.3.1.2 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO {
a : undefined;
b : undefined;
}
2.3.1.3 将实参值和形参统一
AO {
a : 1;
b : undefined;
}
2.3.1.4 在函数体里面找函数声明,值赋予函数体
AO {
a : f a() {};
b : undefined;
d : f () {};
}
2.3.1.5 变量a已经提升声明,即在第2步已经优先声明,此处只需执行a = 123, b = f () {};
AO {
a : 123;
b : f () {};
d : f () {};
}
例子2:
1 | function test(a, b) { |
上面代码的预编译及执行过程如下
2.3.2.1 创建AO对象
AO {
}
2.3.2.2 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO {
a : undefined;
b : undefined;
c : undefined;
}
2.3.2.3 将实参值和形参统一
AO {
a : 1;
b : undefined;
c : undefined;
}
2.3.2.4 在函数体里面找函数声明,值赋予函数体
AO {
a : 1;
b : f b() {};
c : undefined;
d : f d() {};
}
2.3.2.5 变量a已经提升声明,即在第2步已经优先声明,此处只需执行c = 0; a = 3; b = 2;
AO {
a : 3;
b : 2;
d : f () {};
}
例子3:
1 | function test(a, b) { |
上面代码的预编译及执行过程如下
2.3.3.1 创建AO对象
AO {
}
2.3.3.2 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO {
a : undefined;
b : undefined;
}
2.3.3.3 将实参值和形参统一
AO {
a : 1;
b : undefined;
}
2.3.3.4 在函数体里面找函数声明,值赋予函数体
AO {
a : f a() {};
b : undefined;
}
2.3.3.5 变量a已经提升声明,即在第2步已经优先声明,此处只需执行b = 234; a = 123; b = 234; b = f() {};
AO {
a : 123;
b : f() {};
}
注意:
上述在函数体中,生成AO对象,而在全局状态下生成GO对象
window === GO,但能使用window.a,不能使用GO.a
例子4:
1 | console.log(test); |
上面代码的预编译及执行过程如下
2.3.4.1 创建GO对象
GO {
}
2.3.4.2 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
GO {
test : undefined;
}
2.3.4.3 将实参值和形参统一
GO {
test : undefined;
}
2.3.4.4 在函数体里面找函数声明,值赋予函数体
AO {
test : ƒ test(test) {
console.log(test);
var test = 123;
console.log(test);
function test() {}
};
}
2.3.4.5 创建AO对象
AO {
}
2.3.4.6 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO {
test : undefined;
}
2.3.4.7 将实参值和形参统一
AO {
test : 1;
}
2.3.4.8 在函数体里面找函数声明,值赋予函数体
AO {
test : ƒ test() {};
}
2.3.4.9 变量test已经提升声明,即在第2步已经优先声明,此处只需执行test = 123;
AO {
test : 123;
}
例子5:
1 | global = 100; |
上面代码的预编译及执行过程如下
2.3.5.1 创建GO对象
GO {
}
2.3.5.2 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
GO {
global: undefined;
}
2.3.5.3 将实参值和形参统一
GO {
global: undefined;
}
2.3.5.4 在函数体里面找函数声明,值赋予函数体
GO {
global: undefined;
fn : f () {
console.log(global);
global = 200;
console.log(global);
var global = 300;
};
}
2.3.5.5 创建AO对象
AO {
}
2.3.5.6 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO {
global : undefined;
}
2.3.5.7 将实参值和形参统一
AO {
global : undefined;
}
2.3.5.8 在函数体里面找函数声明,值赋予函数体
AO {
global : undefined;
}
2.3.5.9 变量global已经提升声明,即在第2步已经优先声明,此处只需执行global= 200; global = 300;
AO {
global : 300;
}
2.4 百度13年面试题
2.4.1 题目一
2.4.1.1 代码
1 | function bar() { |
上面代码的预编译及执行过程如下
2.4.1.2 创建GO对象
GO {
}
2.4.1.3 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
GO {
}
2.4.1.4 将实参值和形参统一
GO {
}
2.4.1.5 在函数体里面找函数声明,值赋予函数体
GO {
bar : f () {
return foo;
foo = 10;
function foo () {}
var foo = 11;
};
}
2.4.1.6 创建AO对象
AO {
}
2.4.1.7 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO {
foo : undefined;
}
2.4.1.8 将实参值和形参统一
AO {
foo : undefined;
}
2.4.1.9 在函数体里面找函数声明,值赋予函数体
AO {
foo : f () {};
}
2.4.1.10 变量foo已经提升声明,即在第6步已经优先声明,此处只需执行return foo;
AO {
foo : f () {};
}
2.4.2 题目二
2.4.2.1 代码
1 | console.log(bar()); |
上面代码的预编译及执行过程如下
2.4.2.2 创建GO对象
GO {
}
2.4.2.3 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
GO {
}
2.4.2.4 将实参值和形参统一
GO {
}
2.4.2.5 在函数体里面找函数声明,值赋予函数体
GO {
bar : f () {
foo = 10;
function foo () {}
var foo = 11;
return foo;
};
}
2.4.2.6 创建AO对象
AO {
}
2.4.2.7 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO {
foo : undefined;
}
2.4.2.8 将实参值和形参统一
AO {
foo : undefined;
}
2.4.2.9 在函数体里面找函数声明,值赋予函数体
AO {
foo : f () {};
}
2.4.2.10 变量foo已经提升声明,即在第6步已经优先声明,此处只需执行foo = 10; foo = 11; return foo;
AO {
foo : f () {};
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达,可以邮件至 xingshuaikun@163.com。