JavaScript的类字段声明(提案)
栏目: JavaScript · 发布时间: 5年前
内容简介:要定义在单击时递增的计数器窗口组件,可以使用ES2015定义以下内容:使用ESnext字段声明提议,上面的示例可以写成:在上面的示例中,您可以看到使用语法x = 0声明的字段。您还可以将没有初始值设定项的字段声明为x。
要定义在单击时递增的计数器窗口组件,可以使用ES2015定义以下内容:
class Counter extends HTMLElement { clicked() { this.x++; window.requestAnimationFrame(this.render.bind(this)); } constructor() { super(); this.onclick = this.clicked.bind(this); this.x = 0; } connectedCallback() { this.render(); } render() { this.textContent = this.x.toString(); } } window.customElements.define('num-counter', Counter); 复制代码
2. 预先声明属性
使用ESnext字段声明提议,上面的示例可以写成:
class Counter extends HTMLElement { x = 0; clicked() { this.x++; window.requestAnimationFrame(this.render.bind(this)); } constructor() { super(); this.onclick = this.clicked.bind(this); } connectedCallback() { this.render(); } render() { this.textContent = this.x.toString(); } } window.customElements.define('num-counter', Counter); 复制代码
在上面的示例中,您可以看到使用语法x = 0声明的字段。您还可以将没有初始值设定项的字段声明为x。
- 通过预先声明字段,类定义变得更加自我文档化;
- 实例经历较少的状态转换,因为声明的字段始终存在。
私有属性
下面的示例有一些实现细节,属性可以更好地保留在内部。 使用ESnext私有字段和方法,可以将定义细化为:
class Counter extends HTMLElement { #x = 0; clicked() { this.#x++; window.requestAnimationFrame(this.render.bind(this)); } constructor() { super(); this.onclick = this.clicked.bind(this); } connectedCallback() { this.render(); } render() { this.textContent = this.#x.toString(); } } window.customElements.define('num-counter', Counter); 复制代码
要使字段私有,只需给它们一个以#开头的名称。
通过定义在类外部不可见的内容,ESnext提供了更强大的封装,确保您的类的用户不会因为依赖于内部而产生意外。
请注意,ESnext仅在字段声明中提供预先声明的私有字段,正常属性的方式不能创建。
主要设计要点
使用Object.defineProperty创建的公有属性
公有属性声明使用Object.defineProperty(我们在TC39术语中将[[Define]]语义引用)定义实例上的字段,而不是使用this.field = value; (称为[[Set]]语义)。 以下是影响的示例:
class A { set x(value) { console.log(value); } } class B extends A { x = 1; } 复制代码
使用所采用的语义,new B()将导致一个对象具有值为1的属性x,并且不会将任何内容写入控制台。 使用备用[[Set]]语义,1将被写入控制台,并且尝试访问该属性将导致TypeError(因为缺少getter)。
在[[Set]]和[[Define]]之间进行选择是一种设计决策,它对比了不同类型的行为预期:预期字段将作为数据属性创建,而不管超类包含什么;预期setter将被调用。经过长时间的讨论,TC39确定了[[Define]]语义,发现保持第一个期望很重要。
基于Object.defineProperty的公共字段语义的决定是基于TC39内部的广泛讨论和与开发人员社区的协商。不幸的是,社区相当分裂,而TC39则强烈支持Object.defineProperty。
作为一种缓解,decorators建议提供了编写decorator的工具,使公共字段声明使用[[Set]]语义。即使您不同意默认值,也可以使用其他选项。(无论TC39选择哪种缺省值,都是这种情况。)
公共字段在Chrome 72中带有[[Define]]语义,这个语义决定不太可能被重新访问。
没有初始化项的字段被设置为undefined
无论是否存在初始化,公共字段声明和私有字段声明都会在实例中创建一个字段。如果没有初始化器,则将字段设置为undefined。这与某些转置器实现稍有不同,后者将完全忽略没有初始化器的字段声明。
例如,在下面的示例中,new D将生成一个对象,其y属性未定义,而不是1。
class C { y = 1; } class D extends C { y; } 复制代码
将没有初始化项的字段设置为undefined(而不是擦除它们)的语义是,字段声明提供了可靠的基础,以确保在创建的对象上呈现属性。这有助于 程序员 将对象保持在相同的一般状态,这可以很容易地进行推理,有时在实现中更易于优化。
私有语法
私有字段基于使用#的语法,在声明字段和访问字段时都使用#。
class X { #foo; method() { console.log(this.#foo) } } 复制代码
这种语法试图既简洁又直观,尽管它与其他编程语言有很大的不同。 没有私有的计算属性名:#foo是一个私有标识符,#[foo]是一个语法错误。
没有后门访问私有属性
私有字段提供了一个强大的封装边界:从类外部访问私有字段是不可能的,除非有一些显式代码来公开它(例如,提供getter)。这与JavaScript属性不同,JavaScript属性支持各种反射和元编程,而类似于闭包和WeakMap等机制,这些机制不提供对其内部的访问。
执行初始化
在构造函数运行时,公共字段和私有字段都按声明的顺序添加到实例中。初始化器将为每个类实例重新计算。字段在初始化器运行后立即添加到实例中,然后再计算下面的初始化器。
作用域:作为初始化器表达式中的这个值,正在构造的实例位于作用域中。新的。目标未定义,如在方法中。对参数的引用是早期的错误。超方法调用Super .method()在初始化器中可用,但是超构造函数调用Super()是一个语法错误。即使类在异步函数/genenerator中声明,初始化器中也不能使用wait和yield。
当计算字段初始化器并将字段添加到实例时:
- 基类:在构造函数执行的开始,甚至在参数析构之前。
- 派生类:就在super()返回之后。(调用super()的灵活性导致许多实现为这种情况创建了一个单独的不可见initialize()方法。)
如果派生类中没有调用super(),并且没有将其他一些公共和私有字段添加到实例中,也没有计算初始化器。对于基类,初始化器总是被求值,即使构造函数最终返回其他东西。new.initialize proposal将添加一种方法,以编程方式向一个实例添加字段,而该实例不是来自基类中的super()/这个值。
以上所述就是小编给大家介绍的《JavaScript的类字段声明(提案)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- “JavaScript的成员字段提案”或“TC39委员出了什么问题?”
- [译] ECMAScript 的 Observables 提案
- Go 1.15 的提案
- 实用!最新的几个 Vue 3 重要特性提案
- 实用!最新的几个 Vue 3 重要特性提案
- FIBOS 超级节点选举以及提案多签介绍
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
C++沉思录
Andrew Koenig、Barbara Moo / 黄晓春、孟岩(审校) / 人民邮电出版社 / 2002-11-01 / 50.00元
《C++ 沉思录》集中反映了C++的关键思想和编程技术,不仅告诉你如何编程,还告诉你为什么要这样编程。本书曾出现在众多的C++专家推荐书目中。 这将是C++程序员的必读之作。因为: 它包含了丰富的C++思想和技术,从详细的代码实例总结出程序设计的原则和方法。 不仅教你如何遵循规则,还教你如何思考C++编程。 既包括面向对象编程也包括泛型编程。 探究STL这一近年来C++最重要的新成果的内在思想。一起来看看 《C++沉思录》 这本书的介绍吧!