你不懂js系列学习笔记-作用域和闭包- 04

第4章:提升

原文:You-Dont-Know-JS

只有声明本身被提升了,而任何赋值或者其他的执行逻辑都被留在原处。

函数声明和变量声明都会被提升。但函数会首先被提升,然后才是变量。重复的函数声明(避免在同一个作用域内的重复定义),后续的函数声明确实会覆盖前一个。

1 变量声明提升

举例:

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

// 1. var a;
// 2. a = 2;
// 3. console.log( a );
复制代码
console.log( a ); //undefined
var a = 2;

// 1. var a;
// 2. console.log( a );
// 3. a = 2;
复制代码

这种看起来不正常顺序的方式,编译器会帮助引擎整理。

当你看到 var a = 2; 时,你可能认为这是一个语句。但是 JavaScript 实际上认为这是两个语句:var a;a = 2;。第一个语句,声明,是在编译阶段被处理的。第二个语句,赋值,为了执行阶段而留在 原处。

2 函数相关提升

对比上面的例子:

foo();

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

函数 foo 的声明(在这个例子中它还包含一个隐含的、实际为函数的值)被提升了,因此第一行的调用是可以执行的。

函数声明会被提升,就像我们看到的。但是函数表达式不会。

foo(); // 不是 ReferenceError, 而是 TypeError!

var foo = function bar() {
  // ...
};  
复制代码

变量标识符 foo 被提升并被附着在这个程序的外围作用域(全局),所以 foo() 不会作为一个 ReferenceError 而失败。但 foo 还没有值(如果它不是函数表达式,而是一个函数声明,那么它就会有值)。所以,foo() 就是试图调用一个 undefined 值,这是一个 TypeError —— 非法操作。

函数声明和变量声明都会被提升,函数会首先被提升,然后才是变量。

foo(); // 1

var foo;

function foo() {
  console.log(1);
}

foo = function () {
  console.log(2);
};
复制代码

1 被打印了,而不是 2!这个代码段被引擎解释执行为:

function foo() {
  console.log(1);
}

foo(); // 1

foo = function () {
  console.log(2);
};
复制代码

关于重复函数声明被覆盖的坑:

foo(); // "b"

var a = true;
if (a) {
  function foo() { console.log("a"); }
}
else {
  function foo() { console.log("b"); }
}
复制代码

复习

我们可能被诱导而将 var a = 2 看作是一个语句,但是 JavaScript 引擎 可不这么看。它将 var aa = 2 看作两个分离的语句,第一个是编译期的任务,而第二个是执行时的任务。

这将导致在一个作用域内的所有声明,不论它们出现在何处,都会在代码本身被执行前 首先 被处理。你可以将它可视化为声明(变量与函数)被“移动”到它们各自的作用域顶部,这就是我们所说的“提升”。

声明本身会被提升,但不是赋值,即便是函数表达式的赋值,也 不会 被提升。

要小心重复声明,特别是将一般的变量声明和函数声明混在一起 —— 如果你这么做的话,危险就在眼前!

转载于:https://juejin.im/post/5ad574a05188255caf06b2f6

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值