Javascript: смешивание в геттере (распространение объекта)
Я попытался создать смешивание в геттере в объект JS с помощью синтаксиса оператора spread , однако он всегда возвращает 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}
Это ссылается на функцию расширения, которая должна работать, и из того, что я могу сказать выше, код создал непреднамеренное закрытие. Однако он читается довольно плохо по сравнению с синтаксисом ...
. Кто-нибудь знает, как заставить этот код работать последнее решение? Знают ли разработчики ES об этой проблеме и будет ли она исправлена в ES7?
1 ответ:
Это не ошибка. При интерпретации синтаксиса спреда вычисляются значения свойств
mixin
, то есть вызывается геттерwrapper
сthis
, равнымmixin
. Заметим, чтоthis
- это не новый объект, который строится, как...
имеет приоритет над последовательностью запятой. Таким образом, в тот момент, когда выполняется...
, конечный объект не находится в поле зрения. Во-вторых, скопированное свойство больше не является геттером, а обычным свойством с атомарным значением (не a функция).Поведение может быть лучше понято с помощью почти идентичного процесса, который выполняется при использовании
Object.assign
:Object.assign({ wrappername: 'wrapperA' }, mixin);
Если вы хотите, чтобы геттер
wrapper
был вызван с новым объектом как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);
<div id="wrapperA"></div> <div id="wrapperB"></div>
Множественное Наследование
Если вам действительно нужно множественное наследование, то посмотрите на такую библиотеку, как Ring.js , что делает это действительно легким.Есть несколько вопросов и ответов на mixin реализации на StackOverflow . Вот одна из многих идей, выведенных из этой статьи :
"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>
Декораторы
Другой подход заключается в отказе от идеи миксинов и использовании декораторов. вместо этого:
"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>