读懂预编译,不怕作用域面试题
2018-12-04 本文已影响0人
守护银河的河童
我还记得之前很长一段时间被各种作用域面试题支配的恐惧(弱小无助.png)
现在不怕啦,读懂作用域先理解预编译。
来道简单题先:
var a="aa";
function test(){
console.log(a);
var a="bb";
console.log(a);
}
test();
console.log(a);
答案:undefined bb aa
几个概念解释下:
预编译
javascript是解释性语言,主要特点为解释一行执行一行。而在js运行时会进行三件事:
1语法分析
2.预编译
3.解释执行
语法分析会在代码执行前对代码进行通篇检查,以排除一些低级错误,预编译发生在代码执行的前一刻。所以,函数在执行时已经预编译过了。
页面在创建之初就创建了GO(global object)对象,即window对象,所以全局变量也可以叫做window的属性。
1、查找变量,作为GO属性,并赋值undefined。
2、查找函数声明体,作为GO属性,并赋值函数体。
预编译做了些什么事情
1、查看语法错误,如果有错误就不执行接下来的代码。
2、发现有调用函数时,创建AO(activation object)对象。
3、查找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
4、将实参值和形参统一
5、在函数体里面找函数声明,值赋予函数体
现在回到刚才的那道题:
1、创建了GO对象
GO{
a:undefined, //查找变量,作为GO属性,并赋值undefined
test:fun, //查找函数声明体,作为GO属性,并赋值函数体
}
2、执行js
GO{
a:"aa", //变量a已存在,赋值‘aa’
test:fun,
}
3、读到函数调用,创建test函数的AO对象
AO{
a:undefined, //查找变量,作为AO属性,赋值undefined
}
4、执行test 函数
console.log(a) //undefined
此时有2个同名为a的变量,这里涉及到作用域链[[scope]]的概念,但是只要记住,自己有的用自己的,没有的再向父级寻找。
此时,test函数AO对象内有a,且值为undefined,所以打印出来为undefined,
AO{
a:“bb”, //var a = 'bb'给a赋值
}
5、函数执行完毕
console.log(a); // ‘bb’此时的a为全局变量a,父级不能访问子级的私有变量
再来几道题,大家可以把答案写在下面:
var fn
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)
console.log(fn)
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)
console.log(test);
function test(test){
console.log(test);
var test = 123
console.log(test)
function test (){}
}
test(1);
var test = 123
没有声明的变量赋值,默认为全局变量,不管在哪里都默认为全局变量。