【问题标题】:Javascript: Mixing in a getter (object spread)Javascript:在 getter 中混合(对象传播)
【发布时间】:2018-06-05 17:50:56
【问题描述】:

我尝试通过传播 operator 语法在 JS 对象中创建一个 getter 混合,但它似乎总是返回 null

HTML:

<body>
  <div id="wrapperA"></div>
  <div id="wrapperB"></div>
</body>
<script src='./test.js'></script>

JS:

"use strict";

const mixin = {
    get wrapper() { return document.getElementById(this.wrappername); }
}

const wrapperA = {
  wrappername: 'wrapperA',
  ...mixin
}

const wrapperB = {
  wrappername: 'wrapperB',
  ...mixin
}

console.log(wrapperA);
console.log(wrapperB);

控制台输出:

{wrappername: "wrapperA", wrapper: null}
{wrappername: "wrapperB", wrapper: null}

This 链接到一个应该可以工作的扩展函数,据我所知,上面的代码创建了一个无意的闭包。但是,与... 语法相比,它的阅读效果很差。有谁知道如何让代码与后一种解决方案一起使用? ES 开发者知道这个问题吗?会在 ES7 中修复吗?

【问题讨论】:

  • 为什么不简单:class Wrapper { constructor(wrapperId) { this.id = wrapperId; } get wrapper() { return document.getElementById(this.id); }}
  • 1.我倾向于完全避免类,这就是我在特定情况下没有使用它们的原因。
  • 2. (这是1.)多重继承的原因。我也有可能使用原型链,但出于多种原因,我在很大程度上更喜欢 mixins。
  • 结束 body 标记之后的脚本元素是无效的 HTML,因此不应执行该脚本。但是,浏览器可能会更正无效的 HTML 并将脚本放在结束标记之前。
  • "ES7" 是 ECMAScript 2016,它已经被当前版本 ECMAScript 2017 (ed 8) 取代。对象初始化器中的扩展属性可能位于ECMAScript 2018(第 9 版)中。 ;-)

标签: javascript mixins getter-setter ecmascript-next


【解决方案1】:

这不是错误。当扩展语法被解释时,mixin 的每个属性值都会被评估,即调用wrapper getter 时将this 设置为mixin。请注意,this 不是正在构造的新对象,因为 ... has precedence 在逗号排序上。所以在执行... 的那一刻,最终对象不在视图中。其次,复制的属性不再是 getter,而是具有原子值的普通属性(不是函数)。

使用Object.assign 时执行的几乎相同的过程可能会更好地理解该行为:

Object.assign({
  wrappername: 'wrapperA'
}, mixin);

如果您希望以 this 为新对象调用 wrapper getter,请执行以下操作:

"use strict";

class Wrapper {
    constructor(wrappername) {
        this.wrappername = wrappername;
    }
    get wrapper() {
        return document.getElementById(this.wrappername); 
    }
}

const wrapperA = new Wrapper('wrapperA');
const wrapperB = new Wrapper('wrapperB');

console.log(wrapperA.wrapper);
console.log(wrapperB.wrapper);
<div id="wrapperA"></div>
<div id="wrapperB"></div>

多重继承

如果你真的需要多重继承,那么看看像Ring.js这样的库,这真的很容易。

有几个关于 mixin 实现的问答 on StackOverflow。这是众多想法之一,源自this article

"use strict";
function MixinNameGetter(superclass) {
    return class extends superclass {  
        get wrapper() {
            return document.getElementById(this.wrappername); 
        }
    }
}

function MixinLetterGetter(superclass) {
    return class extends superclass {  
        get letter() {
            return this.wrappername.substr(-1); 
        }
    }
}

class Wrapper {
    constructor(wrappername) {
        this.wrappername = wrappername;
    }
}

class ExtendedWrapper extends MixinNameGetter(MixinLetterGetter(Wrapper)) {
}

const wrapperA = new ExtendedWrapper('wrapperA');
const wrapperB = new ExtendedWrapper('wrapperB');

console.log(wrapperA.wrapper, wrapperA.letter);
console.log(wrapperB.wrapper, wrapperB.letter);
<div id="wrapperA"></div>
<div id="wrapperB"></div>

虽然这有效地提供了多重继承,但从表达式派生的类的层次结构并不是高效代码的真正组成部分。

装饰器

另一种方法是放弃 mixins 的想法并改用装饰器:

"use strict";
function DecoratorNameGetter(target) {
    Object.defineProperty(target, 'wrapper', {
        get: function () { 
            return document.getElementById(this.wrappername); 
        }
    });
}

function DecoratorLetterGetter(target) {
    Object.defineProperty(target, 'letter', {
        get: function () {
            return this.wrappername.substr(-1); 
        }
    });
}

class Wrapper {
    constructor(wrappername) {
        this.wrappername = wrappername;
        DecoratorNameGetter(this);
        DecoratorLetterGetter(this);
    }
}

const wrapperA = new Wrapper('wrapperA');
const wrapperB = new Wrapper('wrapperB');

console.log(wrapperA.wrapper, wrapperA.letter);
console.log(wrapperB.wrapper, wrapperB.letter);
<div id="wrapperA"></div>
<div id="wrapperB"></div>

这导致了一个扁平结构(没有原型链),其中扩展发生在目标对象本身中。

【讨论】:

  • class extends 在 mixins 上的做法实在是太可怕了,而且效率低下。
  • 是的,类表达式确实很可怕。我可能应该把它排除在外:P
  • 就像 Bergi 所说的class extends,虽然至少知道它的存在是件好事,但它在代码美学中是令人厌恶的,并且它与原型链接具有相同的缺点。但是,如果您精通 JS 性能,您如何评价我上面链接的 extend 函数?
  • 一个将维护 getter 和 setter 的扩展函数会导致更有效的实现。我还添加了一个关于装饰器的部分。
猜你喜欢
  • 1970-01-01
  • 2011-12-08
  • 2019-02-07
  • 2020-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多