【问题标题】:what is block scope function ECMAScript 6 compare with ECMAScript 5 [duplicate]什么是块范围函数 ECMAScript 6 与 ECMAScript 5 的比较 [重复]
【发布时间】:2016-01-02 09:27:57
【问题描述】:

ECMAScript 6 中的块作用域函数是什么?

谁能帮我了解块作用域功能与 ECMAScript 5 相比的主要区别?

【问题讨论】:

标签: javascript


【解决方案1】:

与古老的var相比,ES2015(又名“ES6”)中新的letconst有四个主要区别:

  1. 它们有块作用域

  2. 它们没有被吊起(嗯,它们是某种被吊起的,但以一种有用的方式)

  3. 重复声明是错误

  4. 在全局范围内使用时,它们不会创建全局对象的属性(尽管创建了全局变量;这是 ES2015 的新概念)

(对于它的价值,这在我最近的书 JavaScript: The New Toys 的第 2 章中有详细介绍,其中涵盖了 ES2015-ES2020。)

块范围

var 变量存在于它们声明的整个函数中(或全局,如果全局声明),它们并不局限于它们所在的块。所以这段代码是有效的:

function foo(flag) {
    a = 10;
    if (flag) {
        var a = 20;
    }
    return a;
}
console.log(foo(false)); // 10
console.log(foo(true));  // 20

a 的定义与flag 是否为真无关,并且它存在于if 块之外;以上三个as 都是同一个变量。

let(或const)不是这样:

function foo(flag) {
    if (flag) {
        let a = 10;
    }
    return a;           // ReferenceError: a is not defined
}
console.log(foo(true));

a 只存在于声明它的块内。(对于 for 语句,for() 内的声明被非常特殊地处理:在块内为 每个循环迭代。)所以在if之外,a不存在。

letconst 声明可以隐藏封闭范围内的声明,例如:

function foo() {
    let a = "outer";

    for (let a = 0; a < 3; ++a) {
        console.log(a);
    }
    console.log(a);
}
foo();

输出

0 1 2 外

...因为for 循环外部的afor 循环内部的a 不同。

吊装

这是有效的代码:

function foo() {
    a = 5;
    var a = a * 2;
    return a;
}

看起来很奇怪,但有效(它返回 10),因为 var 是在函数中完成任何其他操作之前完成的,所以这真的是:

function foo() {
    var a;             // <== Hoisted

    a = 5;
    a = a * 2;         // <== Left where it is
    return a;
}

letconst 不是这样:

function foo() {
    a = 5;            // <== ReferenceError: a is not defined
    let a = a * 2;
    return a;
}

在声明之前,您不能使用该变量。声明没有“提升”(嗯,它是部分提升的,请继续阅读)。

我之前说过

  1. 它们没有被吊起(嗯,它们有点被吊起,但以一种有用的方式)

“有点”?是的。 letconst 声明在它出现的整个块中隐藏标识符,即使它实际上只在它出现的地方生效。示例帮助:

function foo() {
    let a = "outer";

    for (let x = 0; x < 3; ++x) {
        console.log(a);            // ReferenceError: a is not defined
        let a = 27;
    }

}

请注意,我们得到一个错误,而不是在控制台中得到"outer"。为什么?因为for 块中的let a 遮蔽了块外的a,即使我们还没有得到它。块的开头和let 之间的空间被规范称为“时间死区”。语言不是每个人的事,所以这里有一个图表:

重复声明

这是有效的代码:

function foo() {
    var a;

    // ...many lines later...
    var a;
}

第二个var 被忽略。

let(或const)不是这样:

function foo() {
    let a;

    // ...many lines later...
    let a;                     // <== SyntaxError: Identifier 'a' has already been declared
}

不是全局对象属性的全局变量

JavaScript 有一个“全局对象”的概念,它将各种全局事物作为属性。在松散模式下,全局范围内的this 指的是全局对象,而在浏览器中,有一个全局对象指的是全局对象:window。 (其他一些环境提供不同的全局,例如 NodeJS 上的global。)

在 ES2015 之前,JavaScript 中的所有全局变量都是全局对象的属性。在 ES2015 中,使用 var 声明的仍然如此,但使用 letconst 声明的则不然。所以这段代码在全局范围内使用var,在浏览器上显示42:

"use strict";
var a = 42; // Global variable called "a"
console.log(window.a); // Shows 42, because a is a property of the global object

但此代码显示属性的undefined,因为letconst 在全局范围内不会在全局对象上创建属性:

"use strict";
let a = 42; // Global variable called "a"
console.log(a); // 42 (of course)
console.log(window.a); // undefined, there is no "a" property on the global object
const q = "Life, the Universe, and Everything"; // Global constant
console.log(q); // "Life, the Universe, and Everything" (of course)
console.log(window.q); // undefined, there is no "q" property on the global object

最后一点:如果您将新的 ES2015 class(它提供了一种新的、更简洁的语法来创建构造函数和与之关联的原型对象)与函数声明(而不是函数表达式):

  • class 声明具有块范围。相反,在流控制块中使用函数声明是无效。 (这应该是语法错误;相反,不同的 JavaScript 引擎处理它的方式不同。有些将其重新定位到流控制块之外,有些则表现得好像您使用了函数 expression 一样。)李>
  • class 声明没有被提升;函数声明是。
  • 在同一范围内使用相同的名称和两个class 声明是语法错误;使用函数声明,第二个获胜,覆盖第一个。
  • class 全局范围内的声明不会创建全局对象的属性;函数声明。

提醒一下,这是一个函数声明

function Foo() {
}

这些都是函数表达式匿名):

var Foo = function() {
};
doSomething(function() { /* ... */ });

这些都是函数表达式命名):

var Foo = function Foo() {
};
doSomething(function Foo() { /* ... */ });

【讨论】:

  • 这教会了我很多关于 ES6 中变量提升的知识。但问题在于 ES6 中的函数作用域和块作用域函数。
  • @SunnyRGupta:我很高兴它对此有所帮助。 :-) 问题是:不,我认为不是。显然发布问题的人也没有,因为他们已经接受了这个答案。我不认为他们问题中的“功能”一词是字面意思。阅读“机制”而不是“功能”。
猜你喜欢
  • 2011-10-10
  • 2014-03-02
  • 1970-01-01
  • 2012-11-05
  • 1970-01-01
  • 1970-01-01
  • 2011-05-15
  • 2015-08-13
相关资源
最近更新 更多