【JavaScript】变量提升和函数提升

变量提升和函数提升

变量提升

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 才能被调用。

变量提升与函数提升的区别

虽然变量提升和函数提升有一些相似之处,但它们之间存在显著差异,特别是在如何处理变量和函数声明方面。

  1. 变量提升与赋值的分离
    在变量提升中,只有变量的声明会被提升,而赋值操作仍然会留在原地执行。这意味着在变量赋值之前,变量会被提升,但其值会是 undefined。
console.log(x); // 输出:undefined
var x = 5;
console.log(x); // 输出:5
// 上面的代码展示了变量 x 的声明被提升了,但赋值操作并没有被提升,因此在第一次 console.log 中输出的是 undefined。
  1. 函数提升的完整性
    与变量不同,函数提升不仅仅提升了函数名称,还包括了整个函数的定义。因此,在调用函数时,无论该函数定义在调用之前还是之后,都可以正常使用。
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声明变量的那一行代码出现,才能获取和使用该变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值