Javascript:在getter中混合(对象传播)

til*_*boy 2 javascript mixins getter-setter ecmascript-next

我尝试通过扩展运算符语法在getter中创建混合到JS对象中,但它似乎总是返回null.

HTML:

<body>
  <div id="wrapperA"></div>
  <div id="wrapperB"></div>
</body>
<script src='./test.js'></script>
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

控制台输出:

{wrappername: "wrapperA", wrapper: null}
{wrappername: "wrapperB", wrapper: null}
Run Code Online (Sandbox Code Playgroud)

链接到一个应该工作的扩展函数,从我可以告诉上面的代码创建一个无意的闭包.但是,与...语法相比,它的读取效果非常差.有人知道如何让代码与后一种解决方案一起使用吗?ES开发者是否知道这个问题并将在ES7中修复?

tri*_*cot 6

这不是一个错误.解释扩展语法时,将mixin分别评估属性值,即wrapper使用thisset to 调用getter mixin.请注意,this不是正在被建造的新对象,... 具有优先在逗号测序.因此,在...执行时,最终对象不在视野中.其次,复制的属性不再是getter,而是具有原子值(不是函数)的普通属性.

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

Object.assign({
  wrappername: 'wrapperA'
}, mixin);
Run Code Online (Sandbox Code Playgroud)

如果你想wrapper用新对象调用getter this,那么执行:

"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);
Run Code Online (Sandbox Code Playgroud)
<div id="wrapperA"></div>
<div id="wrapperB"></div>
Run Code Online (Sandbox Code Playgroud)

多重继承

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

StackOverflow上有关于mixin实现的几个Q&A .以下是源自本文的众多想法之一:

"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);
Run Code Online (Sandbox Code Playgroud)
<div id="wrapperA"></div>
<div id="wrapperB"></div>
Run Code Online (Sandbox Code Playgroud)

虽然这有效地提供了多重继承,但是从表达式派生的类的结果层次结构实际上并不是高效代码的成分.

装饰

另一种方法是放弃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);
Run Code Online (Sandbox Code Playgroud)
<div id="wrapperA"></div>
<div id="wrapperB"></div>
Run Code Online (Sandbox Code Playgroud)

这导致平面结构(没有原型链),其中扩展发生在目标对象本身中.