为什么ES6类没有吊装

Why are ES6 classes not hoisted?

本文关键字:ES6 为什么      更新时间:2023-09-26

由于 ES6 类只是 JavaScript 现有基于原型的继承的语法糖 [1],因此 (IMO) 提升它的定义是有意义的:

var foo = new Foo(1, 2); //this works
function Foo(x, y) {
   this.x = x;
   this.y = y;
}

但以下方法不起作用:

var foo = new Foo(1, 2); //ReferenceError
class Foo {
   constructor(x, y) {
      this.x = x;
      this.y = y;
   }
}

为什么ES6类不吊装?

为什么ES6类不吊装?

实际上,它们是吊装的(变量绑定在整个范围内可用),就像letconst一样 - 它们只是没有初始化。

提升其定义是有意义的

不。在定义类之前使用类从来都不是一个好主意。考虑示例

var foo = new Bar(); // this appears to work
console.log(foo.x)   // but doesn't
function Bar(x) {
    this.x = x || Bar.defaultX;
}
Bar.defaultX = 0;

并将其与

var foo = new Bar(); // ReferenceError
console.log(foo.x);
class Bar {
    constructor (x = Bar.defaultX) {
        this.x = x;
    }
}
Bar.defaultX = 0;

如您所料,它会引发错误。对于静态属性、原型混合、装饰器和所有内容来说,这是一个问题。它对于子类化也非常重要,当您使用带有未调整原型的类时,子类在 ES5 中完全中断,但现在如果尚未初始化extend ed 类,则会引发错误。

虽然非提升类(在某种意义上说它们的行为类似于let绑定)可以被认为是更可取的,因为它们会导致更安全的使用(参见Bergi的答案),但在2ality博客上找到的以下解释似乎为这种实现提供了一个更基本的原因:

这种限制[非提升]的原因是类可以有一个extends子句,其值是任意表达式。该表达式必须在适当的"位置"进行计算,其计算不能被提升。

在 Javascript 中,所有声明(var、let、const、function、function*、class)都被提升,但它应该在相同的范围内声明。

正如你所说"ES6 类只是 JavaScript 现有的基于原型的继承的语法糖"

那么让我们了解它是什么?

在这里,您声明了一个实际上是"特殊函数"的类。假设你的函数 Foo() 和类 Foo 都在全局范围内。

class Foo {
   constructor(x, y) {
      this.x = x;
      this.y = y;
   }
}

以下是您的类 Foo 的编译代码。

var Foo = (function () {
    function Foo(x, y) {
        this.x = x;
        this.y = y;
    }
    return Foo;
}());

内部,您的类在包装函数 (iife) 中转换为具有相同名称的函数,并且该包装函数返回您的函数。

因为你的函数(类)作用域发生了变化,并且你正在尝试在全局范围内创建实际上不存在的函数对象。

一旦编译开始,你就会在变量Foo中获得函数。 所以稍后你在 var 中有函数,你可以创建它的对象。

类不会被提升,因为,例如,当类扩展表达式而不是函数时,会发生错误:

 class Dog extends Animal {}
 var Animal = function Animal() {
 this.move = function () {
 alert(defaultMove);
 }
 }
var defaultMove = "moving";
var dog = new Dog();
dog.move();

吊装后,这将变成:

var Animal, defaultMove, dog;
class Dog extends Animal {}
Animal = function Animal() {
this.move = function () {
alert(defaultMove);
}
}
defaultMove = "moving";
dog = new Dog();
dog.move();

这样在类 Dog 扩展 动物被解释为动物实际上是未定义的,我们得到一个错误。我们可以通过在声明 Dog 之前移动 Animal 表达式来轻松解决此问题。请看这篇关于该主题的精彩文章:https://blog.thoughtram.io/angular/2015/09/03/forward-references-in-angular-2.html

var foo = new Foo(1, 2); 
//may omit new keyword
var foo=Foo(1,2)
//use class instead of instance by
var fooClass=Foo().constructor
var foo=new fooClass(1,2)
function Foo(x,y){
return new class Foo {
   constructor(x, y) {
      this.x = x;
      this.y = y;
   }
}(x,y)
}