为什么ES6类没有吊装
Why are ES6 classes not hoisted?
由于 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类不吊装?
实际上,它们是吊装的(变量绑定在整个范围内可用),就像let
和const
一样 - 它们只是没有初始化。
提升其定义是有意义的
不。在定义类之前使用类从来都不是一个好主意。考虑示例
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)
}
- 为什么ES6 Fiddle没有't覆盖命名参数
- 为什么javascript ES6 Promises在解析后继续执行
- 为什么ES6 WeakMap's不可枚举
- 为什么我需要的库没有从ES6转换到ES5
- 为什么我们必须在es6箭头函数中用括号包装throw
- 为什么在ES6-react类中需要绑定
- ES6模块:为什么先前导出的模块不为“;“孩子”;模块
- 为什么Chrome无法(或can)在ES6的Arrow函数中找到上下文
- 节点要求()与ES6导入:为什么这个例子不起作用
- 为什么ES6类没有吊装
- JavaScript ES6 'const a = {}' 是可变的.为什么
- 为什么我必须添加尾部'提供商'到服务名称,当我使用es6时
- 为什么我的webpack配置的es6版本会给我一个错误,而es5版本却没有;t
- 使用带有WebPack的ES6模块,为什么还需要
- 为什么在这种情况下调用 ES6 时“产生”是一个保留字
- 为什么我'm得到&;undefined不是函数&;在下面的ES6 for循环中
- 为什么ES6's映射.forEach迭代'value, key'而不是'key, val
- 为什么浏览器需要一个polyfills文件,而我用babel编译ES6到ES5
- 为什么javascript's ES6/Harmony Set对象为键/值/条目方法返回空对象?
- 为什么要在ES6模块上使用模块绑定器