JavaScript递归、预编译
1、JavaScript是解释性语言,执行三部曲如下所示
首先,js对代码进行语法分析,查看有无低级语法错误
然后,进行预编译
最后,解释执行,即解释一行执行一行
2、通用规律
函数声明整体提升,变量声明提升
-
imply global暗示全局变量,即任何变量b,如果变量b未经声明就赋值,此变量就为全局对象所有,全局对象即为window.b可以在函数体外使用
例如:function test() { var a = b = 1; console.log(a); console.log(b); } test(); console.log(b);
2. 一切在全局范围内声明的全局变量,全是window的属性
例如:
var a = 1;
就相当于
window.a = 1;
3、预编译
四部曲:
- 创建AO对象(即Activation Object,执行期上下文)
- 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
- 将实参值和形参统一
- 在函数体里面找函数声明,值赋予函数体
例子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);
上面代码的预编译及执行过程如下
-
创建AO对象
AO { }
-
找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO { a : undefined; b : undefined; }
-
将实参值和形参统一
AO { a : 1; b : undefined; }
-
在函数体里面找函数声明,值赋予函数体
AO { a : f a() {}; b : undefined; d : f () {}; }
-
变量a已经提升声明,即在第2步已经优先声明,此处只需执行a = 123, b = f () {};
AO { a : 123; b : f () {}; d : f () {}; }
例子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);
上面代码的预编译及执行过程如下
-
创建AO对象
AO { }
-
找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO { a : undefined; b : undefined; c : undefined; }
-
将实参值和形参统一
AO { a : 1; b : undefined; c : undefined; }
-
在函数体里面找函数声明,值赋予函数体
AO { a : 1; b : f b() {}; c : undefined; d : f d() {}; }
-
变量a已经提升声明,即在第2步已经优先声明,此处只需执行c = 0; a = 3; b = 2;
AO { a : 3; b : 2; d : f () {}; }
例子3:
function test(a, b) {
console.log(a);
console.log(b);
var b = 234;
console.log(b);
a = 123;
console.log(a);
function a() {}
var a;
b = 234;
var b = function () {}
console.log(a);
console.log(b);
}
test(1);
上面代码的预编译及执行过程如下
-
创建AO对象
AO { }
-
找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO { a : undefined; b : undefined; }
-
将实参值和形参统一
AO { a : 1; b : undefined; }
-
在函数体里面找函数声明,值赋予函数体
AO { a : f a() {}; b : undefined; }
-
变量a已经提升声明,即在第2步已经优先声明,此处只需执行b = 234; a = 123; b = 234; b = f() {};
AO { a : 123; b : f() {}; }
注意:
上述在函数体中,生成AO对象,而在全局状态下生成GO对象
window === GO,但能使用window.a,不能使用GO.a
例子4:
console.log(test);
function test(test) {
console.log(test);
var test = 123;
console.log(test);
function test() {}
}
test(1);
上面代码的预编译及执行过程如下
-
创建GO对象
GO { }
-
找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
GO { test : undefined; }
-
将实参值和形参统一
GO { test : undefined; }
-
在函数体里面找函数声明,值赋予函数体
AO { test : ƒ test(test) { console.log(test); var test = 123; console.log(test); function test() {} }; }
-
创建AO对象
AO { }
-
找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO { test : undefined; }
-
将实参值和形参统一
AO { test : 1; }
-
在函数体里面找函数声明,值赋予函数体
AO { test : ƒ test() {}; }
-
变量test已经提升声明,即在第2步已经优先声明,此处只需执行test = 123;
AO { test : 123; }
例子5:
global = 100;
function test() {
console.log(global);
global = 200;
console.log(global);
var global = 300;
}
test();
var global;
上面代码的预编译及执行过程如下
-
创建GO对象
GO { }
-
找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
GO { global: undefined; }
-
将实参值和形参统一
GO { global: undefined; }
-
在函数体里面找函数声明,值赋予函数体
GO { global: undefined; fn : f () { console.log(global); global = 200; console.log(global); var global = 300; }; }
-
创建AO对象
AO { }
-
找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO { global : undefined; }
-
将实参值和形参统一
AO { global : undefined; }
-
在函数体里面找函数声明,值赋予函数体
AO { global : undefined; }
-
变量global已经提升声明,即在第2步已经优先声明,此处只需执行global= 200; global = 300;
AO { global : 300; }
百度13年面试题
一、题目一
-
代码
function bar() { return foo; foo = 10; function foo () {} var foo = 11; } console.log(bar());
上面代码的预编译及执行过程如下
-
创建GO对象
GO { }
-
找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
GO { }
-
将实参值和形参统一
GO { }
-
在函数体里面找函数声明,值赋予函数体
GO { bar : f () { return foo; foo = 10; function foo () {} var foo = 11; }; }
-
创建AO对象
AO { }
-
找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO { foo : undefined; }
-
将实参值和形参统一
AO { foo : undefined; }
-
在函数体里面找函数声明,值赋予函数体
AO { foo : f () {}; }
-
变量foo已经提升声明,即在第6步已经优先声明,此处只需执行return foo;
AO { foo : f () {}; }
二、题目二
-
代码
console.log(bar()); function bar() { foo = 10; function foo () {} var foo = 11; return foo; }
上面代码的预编译及执行过程如下
-
创建GO对象
GO { }
-
找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
GO { }
-
将实参值和形参统一
GO { }
-
在函数体里面找函数声明,值赋予函数体
GO { bar : f () { foo = 10; function foo () {} var foo = 11; return foo; }; }
-
创建AO对象
AO { }
-
找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO { foo : undefined; }
-
将实参值和形参统一
AO { foo : undefined; }
-
在函数体里面找函数声明,值赋予函数体
AO { foo : f () {}; }
-
变量foo已经提升声明,即在第6步已经优先声明,此处只需执行foo = 10; foo = 11; return foo;
AO { foo : f () {}; }