ES6类构造函数不能被称为普通函数。根据ES6,当这样做时,应该提出TypeError
。我曾经认为类只是原型中构造函数+函数的语法糖,但这使它略有不同。
我想知道,这背后的理由是什么?除非我遗漏了某些内容,否则它会阻止使用自定义this
调用该函数,这可能适用于某些模式。
答案 0 :(得分:0)
重新访问ES6规范,显示 如何通过组合9.2.9和9.2.1节来禁用调用没有new的类函数对象:
9.2.9 MakClassConstructor(F)
...
3.将F的[[FunctionKind]]内部插槽设置为" classConstructor"。
并指定[[call]]方法而不是函数的[[contruct]]方法:
(9.2.1)2。如果F的[[FunctionKind]]内部插槽是" classConstructor",则抛出TypeError异常。
在#34; 11.2.3"功能调用"部分中没有对呼叫功能的限制。 ES5.1。
所以你没有遗漏任何东西:你不能在类构造函数上使用apply
。
主要的理由可能是使类扩展成为一项相当严格的练习,并检测一些早期形式的错误。例如,除了作为构造函数之外,您无法调用Promise
- 并且在调用new
之前遗漏Promise
编程错误。关于扩展类,请注意正确设置了类实例的constructor
属性(可能是多个扩展后的最后一个类),并且类构造函数的.prototype
属性是只读的 - 您可以&#39 ; t动态更改用于构造类实例的原型对象,即使您可以更改构造函数的prototype属性。
我曾经认为课程是语法糖,但已经离开了概念。
答案 1 :(得分:0)
总结一下,你的两个要点是
ES6类构造函数不能被称为普通函数。
它阻止使用自定义调用该函数
首先要注意的是,从类的运行时行为的角度来看,那些点在功能上并没有联系在一起。例如,您可以允许Foo()
不new
,但Foo.call({})
的行为与new
的行为相同。作为函数调用的功能允许设置this
,但它不必,Foo.bind({})()
绑定this
的方式相同然后调用该函数,但绑定的this
将被忽略。
对于决定背后的理由,我无法给你一个主要来源,但我可以告诉你有一个坚实的理由。 ES6类语法是"语法糖",但不是您脑中可能有的简化代码。以您的目标为例,以此片段为例。
class Parent {}
class Child extends Parent {
constructor() {
// What is "this" here?
super();
}
}
Child.call({});
这应该怎么办?在ES6中,super()
是实际设置this
的内容。如果您在调用this
之前尝试访问super()
,则会抛出异常。您的示例代码可能与Base.call({})
一起使用,因为它没有父构造函数,所以this
会在前面初始化,但只要您调用子类, this
预先没有价值。如果您使用.call
,则无法放置该值。
那么接下来的问题是,为什么在this
之前,子课程没有得到super()
?这是因为它允许ES6类语法扩展内置类型,如Array
和Error
和Map
以及任何其他内置构造函数类型。在标准 ES5中,这是不可能的,尽管ES5中的非标准__proto__
可以模拟粗略。即使使用__proto__
,扩展内置类型通常也是一个性能问题。通过在ES6类中包含此行为,JS引擎可以优化代码,以便扩展内置类型工作而不会影响性能。
因此,对于您的问题,是的,他们可以允许Foo.call()
或Foo()
,但无论如何都必须忽略this
才能扩展内置类型。
答案 2 :(得分:0)
这背后的理由是什么?
这是一种保障。当您在没有function
的情况下调用ES5 new
构造函数时,它会执行非常不受欢迎的操作,无声地失败。抛出异常有助于您发现错误。
当然,他们可以选择调用语法与构造相同,但强制使用new
关键字是一件好事,可以帮助我们轻松识别实例化。
它阻止使用自定义
this
调用该函数,这可能适用于某些模式。
是的,这是ES6的根本改变。 this
值由超类初始化,允许具有内部插槽的子类内置 - 有关详细信息,请参阅here。这与传递自定义此参数有冲突,为了保持一致性,我们绝不允许这样做。