JS当中的变量提升(预解析)

函数和变量声明的提升 在JS中存在一个很重要的特性,函数和变量声明的提升,理解这一点对于理解我们编写的代码非常有帮助,那么什么是声明的提升呢?我们通过下面的代码来分析。

console.log(a); //① var a = 123; console.log(a); //②console.log(f); //③ f(); //④ function f() { console.log("函数声明提升"); }

①处的代码如果按照我们以前的理解,代码从上而下执行,那么在执行这行代码的时候,a还没有被声明,所以直接访问一个没有被声明的变量,程序应该报错。
但是结果却大出所料,这里得到的结果是undefined。
③处的结果也和我们最初的认识是不一样的,结果为f对应的函数对象。
造成这个结果是因为变量和函数的作用域提升的原因,什么意思呢?
JS是解释性语言,JS引擎对代码的处理分为两步:
? 预解析处理:在代码执行之前,对代码做全局扫描,对代码中出现的变量或者函数提前声明处理;
? 解析之后我们的代码:
var a; //提前声明,但不初始化 console.log(a); //undefined a = 123; console.log(a); //123//提前声明 function f() { console.log("函数声明提升"); } console.log(f); //函数对象 f(); //函数声明提升

? 调用执行:自上而下的执行代码
变量提升和作用域的关系 题1:
f(); function f() { console.log("1"); } f(); function f() { console.log("2"); } f(); function f() { console.log("3"); }

根据前面对函数声明提升的认识,结果三次都是 “3”。
预解析之后的代码:
function f() { console.log("3"); } f(); f(); f();

为什么解析之后只剩下一个函数,而且是最后那一个?
因为三个函数的名称一样,后面的函数会将前面的覆盖,所以最后只剩下最后一个函数了。
题2:
console.log(a); var a = 123; console.log(a); function f1() { console.log(a); var a = 456; console.log(a); } f1(); console.log(a);

直接先对代码做预解析,然后再做分析。
var a; //变量声明提升 function f1() {//函数声明提升 var a; //变量声明提升 console.log(a); a = 456; console.log(a); } console.log(a); a = 123; console.log(a); f1(); console.log(a);

解析得到上面的代码结果就非常明显了,分别是:undefined 123 undefined 456 123
由于在函数内部有变量a,所以在函数中访问到的是这个局部变量,如果在函数作用域中没有变量a,那么就会跳出函数作用域来到全局作用域来查找。
声明提升的规则 声明提升是将变量或者函数的声明提升到当前作用域的最顶端。在具体使用的过程中存在以下需要注意的细节。
  1. 变量和变量同名,解析之后只存在一个当前变量的声明
console.log(a); var a = 123; console.log(a); var a = 456; console.log(a);

解析之后:
var a; console.log(a); //undefined a = 123; console.log(a); //123 a = 456; console.log(a); //456

  1. 函数和函数同名,后面的声明将前面的覆盖
f(); function f() { console.log("1"); } f(); function f() { console.log("2"); } f(); function f() { console.log("3"); }

解析之后:
function f() { console.log("3"); } f(); //3 f(); //3 f(); //3

  1. 函数和变量同名,函数声明提升,忽略变量的声明
console.log(a); var a = 123; console.log(a); function a() {} console.log(a); function a() {} console.log(a);

解析之后:
function a() {} console.log(a); //函数a var a = 123; //将前面的函数覆盖,a的值变为123 console.log(a); //123 console.log(a); //123 console.log(a); //123

  1. 如果是命名函数,则只将前面的变量声明提升,函数不动。
console.log(fn1); function fn1() { } console.log(fn1); console.log(fn2); var fn2 = function () { } console.log(fn2);

解析之后:
function fn1() { } var fn2; console.log(fn1); //fn1函数 console.log(fn2); //undefined fn2 = function () { } console.log(fn2); //fn2函数

面试题1:
console.log(a,b); //undefined undefined var a=12; var b=13; sum(); //1 function sum(){ console.log(1); }

面试题2:
console.log(a); //undefined var a=12; function fn(){ console.log(a); //undefined var a=13; } fn(); console.log(a); //12

面试题3:
console.log(a); //undefined var a=12; function fn(){ console.log(a); //12 a=13; } fn(); console.log(a)//13

面试题4:
console.log(a); //这个就直接报错了,因为没有变量提升 a is not defined a=12; function fn(){ console.log(a); var a = 13; } fn(); console.log(a)

面试题5:
var foo=1; function bar(){ //不管条件是否成立,都要进行变量提升 //这时的foo属于私有变量 给的默认值是undefined,undefined取反就为真 if(!foo){ var foo=10; } console.log(foo); } bar(); //10

面试题6:
var n=13; function fn(n) { alert(n); // 13 var n=14; //有形参赋值了,就不在走变量提升了 alert(n); // 14 } fn(n); console.log(n); //13

面试题7:
console.log(a); // undefined a=12; function fn(a) { console.log(a); //undefined a=13; } fn(); //注意这里没有传值 var a; console.log(a); //12

面试题8:
function f1() { if("a" in window){//带var的变量提升时不看条件成立不成立的都会提升。 var a = 10; //函数体中声明的变量是局部变量 所以不在window } console.log(a); //undefined } f1();

面试题9:
if(!"a" in window){//使用var声明的全局变量会变成window成员。 var a = 10; } console.log(a); //undefined

面试题10:
console.log(a, b, c); // undefined undefined undefined var a=10,b=20,c=30; function f(a) { console.log(a, b, c); // 10 undefined 30 var b=a=c=100; //a 和 b 是局部变量,只有c是全局变量 console.log(a, b, c); //100 100 100 } f(10,20); console.log(a, b, c); // 10,20,100

面试题11:
function foo() { var num = 123; console.log(num); //123 } foo(); console.log(num); //报错num is not defined

面试题12:
var scope = "global"; foo(); function foo() { console.log(scope); //undefined var scope = "local"; console.log(scope); //local }

面试题13:
var foo = 1; function bar() { if(!foo){//foo变量提升完是undefined取反条件成立 var foo = 10; } console.log(foo); //10 } bar(); console.log(foo); //1

【JS当中的变量提升(预解析)】面试题14:
var arr = [1,2,3,4]; function fun(arr) { arr[0] = 5; arr = [0]; //arr开辟了一个新的地址,指针指向改变 arr[0] = 6; console.log(arr); //[6] return arr } var res = fun(arr); console.log(res); //[6] console.log(arr); //[5,2,3,4]

    推荐阅读