乐趣区

关于javascript:能提升的不只是变量函数声明也可以那谁更吊

思维导图

回顾作用域

在编译的代码生成阶段,编译器会创立在对应作用域创立变量,将 2 者关联起来。

先申明后赋值

讲到 var 申明的变量会进行“变量晋升”,大家可能都感觉不稀奇,然而我这里还是写进去。

a = 2;
var a;
console.log(a); // 2
console.log(a); // undefined
var a = 2;

var申明的变量会进行“变量晋升”

下面的代码会变成这样

var a;
a = 2;
console.log(a); // 2
var a; // 申明未赋值默认值是 undefined
console.log(a); // undefined
a = 2;

编译器先“入手”

总结: 变量和函数在内的所有申明都会在任何代码被执行前首先被解决。

var a = 2;
console.log(a); // 2

下面代码能够看出

var a; // 编译器申明(先,不论在源代码的哪个地位)a = 2;// 代码执行赋值
console.log(a); // 2

函数晋升

总结: 函数申明会被晋升,然而函数表达式却不会被晋升。

foo();
function foo() {console.log(a); // undefined
    var a = 2;
}

下面代码能够写成上面这样

function foo() {
    var a;
    console.log(a); // undefined
    a = 2;
}
foo();

函数表达式不必晋升,函数表达式就是把一个函数赋值给一个变量,既然都是赋值,那么天然不会晋升,只有申明才会晋升。即便是具名的函数表达式,名称标识符在赋值之前也无奈在所在作用域中应用。

foo(); // TypeError 这里 foo 是默认值 undefined(var 的起因)bar(); // ReferenceError
var foo = function bar() {console.log(a); // undefined
    var a = 2;
}

函数优先

函数申明和变量申明都会被晋升。然而函数会首先被晋升,而后才是变量

foo(); // 1
var foo;
function foo() {console.log(1);
}
foo = function () {console.log(2);
};

下面代码 foo() 是 1 不是 TypeError。所以函数申明是比变量申明更优先。

foo(); // TypeError: foo is not a function

function foo() {console.log(2);
};
var foo; // 被疏忽

函数申明还是能够笼罩

foo(); // 3
function foo() {console.log(1);
}
var foo = function () {console.log(2);
};
function foo() {console.log(3);
}

总结 申明自身会被晋升,而包含函数表达式的赋值在内的赋值操作并不会晋升。

退出移动版