资讯专栏INFORMATION COLUMN

JavaScript 变量声明提升

fireflow / 2972人阅读

摘要:输出的结果为输出的结果为提升后输出的结果为重新定义了变量输出的结果为如果定义了相同的函数变量声明,后定义的声明会覆盖掉先前的声明,看如下代码输出练习的值是多少的值是多少第二题的解析请看这里参考资料文章文章中文版链接文章推荐文章变量提升

JavaScript 变量声明提升

原文链接

一个小例子

先来看个例子:

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

为什么是这样的结果呢?这是因为 JavaScript 代码在执行之前会有一个 预解析 阶段,在这个阶段,解释器会将所有 变量声明函数声明 提升到他们各自的作用域顶部。

注:变量声明提升只是预解析阶段的一部分行为!

如果变量在函数体内声明,它的作用域是函数作用域(function-level scope)。否则,它就是全局作用域。

继续上面的例子,因为这个预解析阶段,上面的代码会被解释器预解析成下面的代码:

var a;
console.log(a);    // undefined
a = 2;
console.log(a);    // 2
变量的声明

在 ES6 之前,通常通过 var 来声明一个变量,但是 ES6 发布后,又新添了2个关键字来声明一个变量:letconst

var 声明了一个变量,这个变量的作用域是当前执行位置的上下文:一个函数的内部(声明在函数内)或者全局(声明在函数外)

let 声明了一个块级域的局部变量,并且它声明的变量只在所在的代码块内有效

const 声明了一个只读的块级域的常量,并且它声明的常量也只在所在的代码块内有效

{ // 代码块
  var a = 1;
  let b = 2;
  const c = 3;
  
  console.log(a);   // 1
  console.log(b);   // 2
  console.log(c);   // 3
}

console.log(a);   // 1
console.log(b);   // 报错,ReferenceError: b is not defined(…)
console.log(c);   // 未执行, 因为上面语句出错,所以这条语句不再执行,如果上面的语句不报错,那么这里就会报错
(function (){
  var a = 1;
  let b = 2;
  const c = 3;
  
  console.log(a);   // 1
  console.log(b);   // 2
  console.log(c);   // 3
})();   // 为了方便,这里使用了自执行函数

console.log(a);   // 报错,ReferenceError: a is not defined(…)
console.log(b);   // 未执行
console.log(c);   // 未执行

let const 不像 var 那样会发生“变量提升”现象。

console.log(a);    // 报错,ReferenceError: a is not defined
let a = 2;
console.log(a);    // 待执行
console.log(a);    // 报错,ReferenceError: a is not defined
const a = 2;
console.log(a);    // 待执行

ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

变量声明提升(Variable hoisting)

提升(hoisting)影响了变量的生命周期,一个变量的生命周期包含3个阶段:

声明 - 创建一个新变量,例如 var myValue

初始化 - 用一个值初始化变量 例如 myValue = 150

使用 - 使用变量的值 例如 alert(myValue)

当代码按照这三个步骤的顺序执行的时候,一切看起来都很简单,自然。

变量提升的部分只是变量的声明,赋值语句和可执行的代码逻辑还保持在原地不动

console.log(a);     // undefined
var a = 111;
function fun(){
  console.log(a);   // undefined
  var a = 222;
  console.log(a);   // 222
}
fun();
console.log(a);     // 111

// --------------
//变量提升后

function fun(){
  var a;
  console.log(a);   // undefined
  a = 222;
  console.log(a);   // 222
}
var a;
console.log(a);     // undefined
a = 111;
fun();
console.log(a);     // 111

在基本的语句(或者说代码块)中(比如:if语句for语句while语句switch语句for...in语句等),不存在变量声明提升

var a = "aaa";
{
  console.log(a);       // aaa
  var a = "bbb";
}
console.log(a);         // bbb

//---------------

var a = "aaa";
if (true) {
  console.log(a);       // aaa
  var a = "bbb";
}
console.log(a);         // bbb

//---------------

var a = "aaa";
for(let x in window){
  console.log(a);       // aaa
  var a = "bbb";
  break;
}
console.log(a);         // bbb
函数声明提升(Function Hoisting)

函数声明(function declarations) 和 函数表达式(function expressions)在语法上其实是等价的,但是有一点不同,就是 JavaScript 引擎 加载他们的方式不一样。简单讲,就是函数声明会被提升到其作用域顶部,而函数表达式不会。

更多细节

函数声明会提升,但是函数表达式的函数体就不会提升了

fun();       // hello 

function fun(){
  console.log("hello");
}

// --------------
// 提升后

function fun(){
  console.log("hello");
}

fun();       // hello 
fun();       // 报错,TypeError: fun is not a function

var fun = function(){
  console.log("hello");
};

// --------------
// 提升后

var fun;

fun();        // 报错,TypeError: fun is not a function

fun = function(){
  console.log("hello");
};

当函数表达式的函数不再是匿名函数,而是一个有函数名的函数时,会发生什么?

foo();  // 报错,TypeError "foo is not a function"
bar();  // 有效的
baz();  // 报错,TypeError "baz is not a function"
spam(); // 报错,ReferenceError "spam is not defined"

// anonymous function expression ("foo" gets hoisted)
var foo = function () {};     

// function declaration ("bar" and the function body get hoisted)
function bar() {}; 

// named function expression (only "baz" gets hoisted)
var baz = function spam() {}; 

foo(); // 有效的
bar(); // 有效的
baz(); // 有效的
spam(); // 报错,ReferenceError "spam is not defined"

如果一个变量和函数同名,函数声明优先于变量声明(毕竟函数是 JavaScript 的第一等公民),并且与函数名同名的变量声明将会被忽略。

fun();    // 输出的结果为111
function fun(){
  console.log(111);
}
var fun = function(){
  console.log(222);
}
fun();    // 输出的结果为222 

// --------------
// 提升后

function fun(){
  console.log(111);
}
fun();    // 输出的结果为111
fun = function(){       // 重新定义了变量 fun
  console.log(222);
}
fun();    // 输出的结果为222 

如果定义了相同的函数变量声明,后定义的声明会覆盖掉先前的声明,看如下代码:

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

alert(foo) 的值是多少?

var foo = 1;
function bar() {
    if (!foo) {
        var foo = 10;
    }
    alert(foo); // ?
}
bar();

alert(a) 的值是多少?

var a = 1;
function b() {
    a = 10;
    return;
    function a() {}
}
b();
alert(a);  // ?

第二题的解析请看 这里

参考资料

【文章】Variable and Function Hoisting in JavaScript

【文章】JavaScript variables hoisting in details(中文版链接)

【文章】JavaScript Scoping and Hoisting(推荐)

【文章】JavaScript变量提升

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80247.html

相关文章

  • javascript声明提升

    摘要:但是碰到声明提升,这种想法就会被打破。声明一个函数进行相应的操作,会得到函数声明提升的结果。由此可以发现变量和函数的声明都会被提升在其他代码的前面执行。一个普通块内部的函数声明通常会被提升到所在的作用域的顶部。的创建初始化和赋值均会被提升。 Javascript声明提升 在分析声明提升之前,我认为有必要知道的两点: 一、引擎查询变量的两种方式 引擎查询变量的方式可以分为LHS和RHS两...

    evin2016 评论0 收藏0
  • ES6 变量作用域与提升变量的生命周期详解

    摘要:不同的是函数体并不会再被提升至函数作用域头部,而仅会被提升到块级作用域头部避免全局变量在计算机编程中,全局变量指的是在所有作用域中都能访问的变量。 ES6 变量作用域与提升:变量的生命周期详解从属于笔者的现代 JavaScript 开发:语法基础与实践技巧系列文章。本文详细讨论了 JavaScript 中作用域、执行上下文、不同作用域下变量提升与函数提升的表现、顶层对象以及如何避免创建...

    lmxdawn 评论0 收藏0
  • Javascript中的变量提升、函数提升变量访问原则

    摘要:变量提升什么是变量提升在函数体内声明的变量,无论你是在函数的最底端还是中间声明的,那么都会把该变量的声明提升到函数的最顶端相当于第一行,但是只是提升变量的声明,不会赋值。 1、变量提升 什么是变量提升?在函数体内声明的变量,无论你是在函数的最底端还是中间声明的,那么都会把该变量的声明提升到函数的最顶端(相当于第一行),但是只是提升变量的声明,不会赋值。 var num = 10; fu...

    zhigoo 评论0 收藏0
  • 【6】JavaScript 函数高级——执行上下文与执行上下文栈、变量提升(图解+典型实例分析)

    摘要:函数和变量相比,会被优先提升。这意味着函数会被提升到更靠前的位置。仅提升声明,而不提升初始化。 JavaScript 函数高级——执行上下文与执行上下文栈(图解+典型实例分析) 变量提升与函数提升 变量声明提升 通过 var 定义(声明)的变量,在定义语句之前就可以访问到 值:undefined /* 面试题 : 输出 undefined */ var a = 3 ...

    niuxiaowei111 评论0 收藏0
  • JavaScript变量提升

    摘要:变量提升需要注意两点提升的部分只是变量声明,赋值语句和可执行的代码逻辑还保持在原地不动提升只是将变量声明提升到变量所在的变量范围的顶端,并不是提升到全局范围,说明如下会输出变量提升之后的效果函数声明会提升,但是函数表达式就不了。 问题 有些朋友可能会觉得javascript的代码是从上到下,一行一行的解释执行的。如果按照这样的思路,在有些情况下阅读代码会得到错误的结果,考虑以下代码: ...

    Zoom 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<