变量提升和函数提升
变量提升
JS解析时,会先找到代码中所有的变量声明,然后将其放在作用域的头部,变量提升只会提升其中的变量声明,而不会提升其赋值操作。变量提升的特点:
(1)只在var声明时提升,let和const不会提升
(2)提升的只能是声明,不是赋值
(3)只在当前作用域内提升
变量提升的主要目的是使得代码在执行时能够顺利运行,因为 JavaScript 是一种解释执行的语言,它在执行代码之前会进行解析和编译。通过变量提升,JavaScript 引擎可以提前知道哪些变量和函数在作用域中可用,从而避免了在执行过程中出现未定义的情况。变量提升可以使函数之间相互调用。
- 解析和预编译过程中的声明提升可以提高性能,让函数可以在执行时预先为变量分配栈空间。
- 声明提升还可以提高JS代码的容错性,使一些不规范的代码也可以正常执行。
函数提升
与变量提升类似,函数声明也会被提升到其作用域的顶部。不同的是,函数声明不仅会提升其名称,还会提升整个函数体。因此,即使在函数声明之前调用该函数,代码仍然可以正常执行。
console.log(foo()); // 输出:Hello!
function foo() {
return "Hello!";
}
// 在上述代码中,函数 foo 在调用之前就已经声明和定义,因此即使在函数定义之前调用它,依然能够正常执行。
函数表达式
函数表达式只会提升声明,不会提升赋值!
虽然函数声明会被提升,但函数表达式却不会被提升。这是因为函数表达式中的函数定义是赋值操作,而赋值操作不会被提升。函数表达式是在赋值语句中定义的函数,与函数声明不同,函数表达式的提升行为与变量提升相同,即仅提升变量声明,不提升赋值部分。
console.log(baz); // 输出:undefined
var baz = function() {
return "Hi!";
};
console.log(baz()); // 输出:Hi!
// 在这段代码中,baz 是一个函数表达式,它的声明被提升了,但函数赋值操作没有被提升,因此在第一次 console.log 时,baz 的值是 undefined。只有在函数赋值完成后,baz 才能被调用。
变量提升与函数提升的区别
虽然变量提升和函数提升有一些相似之处,但它们之间存在显著差异,特别是在如何处理变量和函数声明方面。
- 变量提升与赋值的分离
在变量提升中,只有变量的声明会被提升,而赋值操作仍然会留在原地执行。这意味着在变量赋值之前,变量会被提升,但其值会是 undefined。
console.log(x); // 输出:undefined
var x = 5;
console.log(x); // 输出:5
// 上面的代码展示了变量 x 的声明被提升了,但赋值操作并没有被提升,因此在第一次 console.log 中输出的是 undefined。
- 函数提升的完整性
与变量不同,函数提升不仅仅提升了函数名称,还包括了整个函数的定义。因此,在调用函数时,无论该函数定义在调用之前还是之后,都可以正常使用。
console.log(bar()); // 输出:42
function bar() {
return 42;
}
// 在这段代码中,函数 bar 的完整声明和定义都被提升到了作用域的顶部,因此函数调用在函数定义之前也是合法的
举个例子:
// 例子1:
/*
下面的代码变量提升为:
var b
b = function b(){
console.log('b2')
};
// 正常执行的剩余代码块
console.log(b);
b = function(){
console.log('b1')
};
console.log(b)
*/
console.log(b); // 打印b2,函数会提升,函数表达式不会提升赋值
var b = function(){
console.log('b1')
};
function b(){
console.log('b2')
};
console.log(b); // 打印b1
// 例子二:同名参数名,变量名,函数名同时存在
/*
var m
m = 10 传入的参数会在函数提升的前面,被覆盖
function m
console.log(m);
m = 1
console.log(m);
*/
function fn (m){
console.log(m); //[Function: m]
var m = 1; // 只会提升定义
function m(){
}
console.log(m); // 1
}
fn(10)
ES6提出了let、const
解决变量提升问题,let、const声明的变量有自身的作用域,且不能挂载到window上。存在暂时性死区。let定义变量,const定义常量,或者是定义引用数据类型,改变值但不改变引用的地址。
暂时性死区
暂时性死区(在变量声明之前属于该变量的死区):let和const使区块形成封闭的作用域,在未声明变量前使用变量就会出现暂时性死区,是一种语法错误。在代码块内,使用let或const命令声明变量之前,该变量都是不可用的,在变量声明之前属于该变量的“死区”,这在语法上被称为“暂时性死区”。
意义:ES6规定暂时性死区和let、const语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。暂时性死区的本质是,只要一进入当前作用域,所使用的变量就已经存在了,但是不可获取。只有等到let或const声明变量的那一行代码出现,才能获取和使用该变量。