预编译也是js中非常重要的概念之一,看完了成哥的js课程中的预编译后,我不敢说十分的清除,也敢说有个六七分的掌握啦~今天自己总结一下自己的所学,与大家分享,有不对的地方还请不吝赐教:)
预编译的规则
请牢记以下规则:
- 函数声明整体提升
- 变量仅声明提升(赋值不提升)
- 当函数声明和变量重名时,只生产一个变量
举个栗子吧:
// 1. 函数声明整体提升
testFn(); //123
function testFn() {
console.log(123);
}
//2. 变量仅声明提升(赋值不提升)
console.log(a);// 声明并赋值 undefined
var a = 1;
console.log(a);// 1
// consol.log(b); //未声明,报错 Uncaught ReferenceError: consol is not defined
// 3. 函数及变量重名时---覆盖
console.log(demo);// 函数demo
function demo(demo) {
var demo = 2211;
var demo = function () {
console.log("demo()-demo()")
}
console.log("demo");
}
var demo = 1122;
console.log(demo);// 1122
函数环境中的预编译
一、请牢记以下规则
- 创建AO对象 (活跃对象 activation object 执行期上下文)
- 找形参和变量声明,将形参名和变量作为AO对象的属性名,值为undefined
- 将实参值和形参统一
- 在函数体里面找函数声明,值赋予函数体 这样看或许不太好理解,还是举栗子吧:
function fn(a) {
console.log(a);//AO.a function a() { console.log("a") }
var a = 123;
console.log(a);//123
function a() { console.log("a") }//预编译处理过的就不用看了
console.log(a);//123
var b = function () { console.log("b"); }
console.log(b);//AO.b function(){ console.log("b"); }
function d() { console.log("d"); }
}
fn(100);
没学过预编译的时候,我真的一头雾水,一堆的a、b、c、变量、函数,到底哪个是哪个,现在请还不懂的你跟着我的思路:
第一步:创建一个AO对象。
AO = {}
第二步:找到所有形参和变量名,作为AO的属性,且值为undefined。
AO = {
a:undefined
b:undefined
}
第三步:统一实参和形参。
// 实参只有一个:100
// 形参只有一个:a
AO = {
a:100,
b:undefined
}
第四步:找到函数体里面的函数声明,并将函数体作为值赋给函数名
AO = {
a:function a() { console.log("a") },
b:undefined
d:function (){console.log("d");}
}
预编译就结束了,代码执行的过程中,就一行一行的执行代码就可以啦~ 接着分析下执行过程吧:
// 从上面的AO对象里查找a的值,打印function a() { console.log("a") }
console.log(a);
// 碰到赋值语句,修改AO对象
var a=123;
AO {
a:123,
b:undefined,
d:function d(){ console.log("b"); },
}
// 函数表达式在预编译处理过了,就跳过
function a() { console.log("a") }
// 从最新的AO对象里找到a的值,打印123
console.log(a);
// 碰到赋值语句,修改AO对象
var b = function(){ console.log("b"); }
AO {
a:123
b:function(){ console.log("b"); }
d:function d(){ console.log("d"); }
}
// 从AO对象中取到b的值,打印function(){ console.log("b"); }
console.log(b);
// 函数表达式在预编译第四步处理过,就跳过
function d() { console.log("d"); }
明白了吧?在调用函数的同时创建了函数的执行器上下文AO对象,并将形参、变量和函数声明作为该对象的属性,函数声明的值为函数体,变量的值为undefined,形参的值取决于实参。 然后就是执行函数体内的语句。碰到赋值语句就更新AO,遇到函数声明就跳过,遇到打印语句就去当前的AO找值。是不是很容易就搞清楚啦?
下面再吃几个栗子巩固以下吧:
二、例题
例一
function test(a,b){
console.log(a); //1
c=0; //AO.c=0
var c;
a=3; //AO.a=3
b=2;//AO.b=2
console.log(b);//2
function b(){ console.log("b"); }
function d(){ console.log("d"); }
console.log(b);//2
}
test(1);
答案:
1. AO{}
2. 形参和变量名
AO{
a:undefined,
b:undefined,
c:undefined
}
3. 形参实参统一值
AO{
a:1,
b:undefined,
c:undefined
}
3. 找函数声明并赋值
AO{
a:1,
b:function b(){ console.log("b"); },
c:undefined,
d:function d(){ console.log("d"); }
}
例二
function func(a,b){
console.log(a,b);// function a(){ console.log("a") } undefined
var b = 234;// AO.b=234
console.log(b);//234
a=123;//AO.a=123
console.log(a);//123
function a(){ console.log("a") }
var a;
b=432;//AO.b=432
var b = function (){ console.log("b") }// AO.b=function (){ console.log("b") }
console.log(a,b);//123 function (){ console.log("b") }
}
func(1);
答案:
1. AO{}
2. AO{
a:undefined,
b:undefined
}
3. AO{
a:1,
b:undefined
}
4. AO{
a:function a(){ console.log("a") },
b:undefined
}
全局环境下的预编译
一、规则
- GO global object====window
- 找变量
- 找函数声明,并用函数体赋值
二、例题
例一
console.log(ff); // function ff(ff){....}
function ff(ff){
console.log(ff);// function ff(){ console.log("ff"); }
var ff=1234;//AO.ff=1234
console.log(ff);//1234
function ff(){ console.log("ff"); }
}
ff(1122);
var ff=2233;
答案:
GO{}
GO{
ff:undefined
}
GO{
ff:function ff(ff){
console.log(ff);
var ff=1234;
console.log(ff);
function ff(){ console.log(ff); }
}
}
AO{}
AO{
ff:undefined
}
AO{
ff:1122
}
AO{
ff: function ff(){ console.log("ff"); }
}
例二
var glo = 100;//GO.glo=100
function ffn() {
console.log(glo);
}
ffn();//100
答案:
GO{}
GO{
glo:undefined,
ffn:function ffn(){...}
}
AO{}
例三
global = 100;
function fnn() {
console.log(global);//undefined
global = 200;//AO.Global=200
console.log(global);//200
var global = 300;
}
fnn();
var global;//声明提升到最前面
答案:
GO{}
GO{
global:undefined
fnn:function fnn(){....}
}
AO{}
AO{
global:undefined
}
例四
function ffnn() {
console.log(p);//undefined
if (m) {//undefined
var p = 100;
}
console.log(p);//undefined
k = 234;//GO.c=234
console.log(k);//234
}
var m;
ffnn();
m = 10;
console.log(k);//234
答案:
GO{}
GO{
m:undefined
ffnn:function ffnn(){...}
}
AO{}
AO{
p:undefined
}
例五
console.log(bar1());//11
function bar1() {
foo = 10;//AO.foo=10
function foo() { console.log("foo") }
var foo = 11;//AO.foo=11
return foo;//11
}
答案:
GO{}
GO{
bar1:function bar1(){...}
}
AO{}
AO{
foo:undefined
}
AO{
foo:function foo(){ console.log("foo")}
}
2013百度面试题
function bar() {
return foo;
roo = 10;
function foo() { console.log("foo") }
var foo = 11;
}
console.log(bar());//foo:function foo(){ console.log("foo")}
答案:
GO{}
GO{
bar:function bar(){...}
}
AO{}
AO{
foo:undefined
}
AO{
foo:function foo(){ console.log("foo")}
}
再来一道巩固题吧,加油
第一题
a = 100;//GO.a=100
function dd(e) {
function e() { console.log("e"); }
arguments[0] = 2;//AO.e=2
console.log(e);//2
console.log(a);//就近原则--找到AO.a=undefined
if (a) {//undefined
var b = 123;
function c() { console.log("c"); }//现实中:if语句中不允许声明function,所以还是undefined
}
var c;
a = 10;//AO.a=10
var a;
console.log(b);//undefined
f = 123;//GO.f=123
console.log(c);//undefined
console.log(a);//10
}
var a;
dd(1)
console.log(a);//GO.A=100
console.log(f);//GO.f=123
答案:
GO{}
GO{
a:undefined,
dd:function dd(){...}
}
AO{}
AO{
e:undefined,
b:undefined,
c:undefined,
a:undefined
}
AO{
e:1,
b:undefined,
c:undefined,
a:undefined
}
AO{
e:function e(){ console.log("e");},
b:undefined,
c:undefined (理想:function c(){console.log("c");}),
a:undefined
}