今天,我有一个重构JS代码的小任务,并且遇到了该语言的意外功能,在此方面我有超过7年的编程经验 被许多人讨厌 语言没有思考,也没有遇到。
此外,我在俄语或英语互联网上都找不到任何内容,因此决定发布此书的时间不长,不是最有趣但有用的注释。
为了不使用传统的,毫无意义的foo/bar
常量,我将直接在项目中使用的示例中显示,但仍然没有一堆内部逻辑并且带有假值。 请记住,所有这些示例都是完全综合的。
我们踩耙
所以我们有一个类:
class BaseTooltip { template = 'baseTemplate' constructor(content) { this.render(content) } render(content) { console.log('render:', content, this.template) } } const tooltip = new BaseTooltip('content')
一切都是合乎逻辑的
然后,我们需要创建另一种类型的工具提示,其中的template
字段会发生变化
class SpecialTooltip extends BaseTooltip { template = 'otherTemplate' }
这让我感到惊讶,因为在创建新类型的对象时,会发生以下情况
const specialTooltip = new SpecialTooltip('otherContent')
正如我所期望的BaseTooltip.prototype.template
,使用值BaseTooltip.prototype.template
而不是SpecialTooltip.prototype.template
BaseTooltip.prototype.template
了render方法。
我们小心地踩着耙子, 拍摄影片
由于chrome DevTools不知道如何分配类字段,因此您必须借助技巧来了解正在发生的事情。 使用一个小助手,我们记录分配给变量的时刻
function logAndReturn(value) { console.log(`set property=${value}`) return value } class BaseTooltip { template = logAndReturn('baseTemplate') constructor(content) { console.log(`call constructor with property=${this.template}`) this.render(content) } render(content) { console.log(content, this.template) } } const tooltip = new BaseTooltip('content')
当我们将这种方法应用于继承的类时,会遇到以下奇怪的情况:
class SpecialTooltip extends BaseTooltip { template = logAndReturn('otherTemplate') } const tooltip = new SpecialTooltip('content')
我确定对象的字段首先被初始化,然后构造函数的其余部分被调用。 事实证明,一切都比较棘手。
我们踩着耙子,给茎上油漆
我们通过向构造函数添加另一个参数使情况复杂化,该参数分配给我们的对象
class BaseTooltip { template = logAndReturn('baseTemplate') constructor(content, options) { this.options = logAndReturn(options)
而且只有这种调试方式(嗯,不是警报)可以澄清一点
这个问题是从哪里来的:以前,此代码是在Marionette框架上编写的,并且(有条件地)看起来像这样
const BaseTooltip = Marionette.Object.extend({ template: 'baseTemplate', initialize(content) { this.render(content) }, render(content) { console.log(content, this.template) }, }) const SpecialTooltip = BaseTooltip.extend({ template: 'otherTemplate' })
使用Marionette时,一切工作都与我预期的一样,即使用类中指定的template
值调用render
方法,但是将模块逻辑复制到ES6时,本文中描述的问题就解决了
计算颠簸
结果:
创建继承类的对象时,发生的顺序如下:
- 从继承的类声明中初始化对象字段
- 继承类的构造函数的执行(包括构造函数内部字段的初始化)
- 仅在初始化当前类中的对象的字段之后
- 执行当前类的构造函数
我们把耙子还给谷仓
具体来说,在我的情况下, 可以通过mixins或将模板传递给构造函数来解决问题,但是当应用程序逻辑需要覆盖大量字段时,这将成为一种相当肮脏的方式。
最好在评论中阅读您对如何优雅地解决问题的建议。