组合与继承及其在 Javascript 中的成本
Posted
技术标签:
【中文标题】组合与继承及其在 Javascript 中的成本【英文标题】:Composition vs Inheritance and their costs in Javascript 【发布时间】:2021-03-27 23:59:24 【问题描述】:我刚刚发现了 javascript 中的组合,我一直认为继承是编写 javascript 的标准方式。 我没有得到的是,如果我使用一个类并从另一个类继承例如两个方法,每次我创建一个新实例并控制台记录它时,该对象只有它的“本地”属性,没有继承的迹象方法,这是显而易见的。 但是,现在如果我对组合做同样的事情,每次我创建一个新对象并在控制台记录它时,每个新创建的对象现在也都有方法。
我们不是在重复代码吗? ,在不同的对象中。我在这里遗漏了什么吗?
【问题讨论】:
看看这个:***.com/questions/8696695/… 这能回答你的问题吗? Composition, Inheritance, and Aggregation in JavaScript 你具体指的是什么“组成”?编程中有很多东西叫做“组合”。 @Anthony ... 还有什么问题吗? 【参考方案1】:继承(并重复 OP)
实例本身并不拥有继承的方法。如果使用这样的方法调用,解释器确实会开始查找原型链以寻找匹配的方法。一旦找到该方法,它就会在该方法的目标对象之前的实例的上下文中被调用。
因此,实例不具有用于继承方法的自己的槽/属性,而是依赖于 JavaScript 内置的自动委托机制,因此继承基于原型委托。
class FirstLastItemList extends Array
// inheritance via prototype methods.
first() return this[0];
last() return this[this.length - 1];
const list_A_1 = new FirstLastItemList("A", "B", "C");
const list_A_2 = new FirstLastItemList(2, 3, 4, 5, 6);
const list_B_1 = new FirstLastItemList("D", "C", "B");
const list_B_2 = new FirstLastItemList(6, 5, 4, 3, 2);
console.log('list_A_1.first() :', list_A_1.first());
console.log('list_A_2.first() :', list_A_2.first());
console.log('list_B_1.last() :', list_B_1.last());
console.log('list_B_2.last() :', list_B_2.last());
console.log('\n');
console.log(
'(list_A_1.first === list_B_2.first) ?',
(list_A_1.first === list_B_2.first),
'...inherited code'
);
console.log(
'(list_A_2.last === list_B_1.last) ?',
(list_A_2.last === list_B_1.last),
'...inherited code'
);
console.log('\n');
console.log(
'Object.getOwnPropertyNames(list_A_1) :',
Object.getOwnPropertyNames(list_A_1)
);
console.log(
'Object.getOwnPropertyNames(FirstLastItemList.prototype) :',
Object.getOwnPropertyNames(FirstLastItemList.prototype)
);
.as-console-wrapper min-height: 100%!important; top: 0;
通过基于函数的 mixins 的示例组合技术(并回答 OP)
我们不是在重复代码吗,你知道,一遍又一遍地重复相同的方法吗? ,在不同的对象中。我在这里错过了什么吗?
简而言之,答案是……“是的,但应该注意,并且仍然可以控制不同组合技术带来的占用空间或内存使用情况。”
首先,通过组合,总是会向对象添加(一个)自己的属性。对于任何新分配的方法,可以为其提供完整的实现,也可以仅提供对后者的引用。
这对于两种最常见的基于 mixin 的组合形式也是如此,即任何基于 Object.assign
或基于函数的 mixin 的胶水代码。
提供的示例确实选择了基于函数的 mixin 方法,以促进这种形式的代码重用(但同样的想法也适用于其基于对象的对应物)...
function firstListItemMixinWithCodeDuplication()
// - duplication of both, slot and implementation/code.
this.first = () => this[0];
function last()
// implement code once ...
return this[this.length - 1];
function lastListItemMixinWithSharedReference()
// ... then reuse via reference ...
// - duplicated slot but shared implementation/code.
this.last = last;
const list_A_1 = ["A", "B", "C"];
const list_A_2 = [2, 3, 4, 5, 6];
const list_B_1 = ["D", "C", "B"];
const list_B_2 = [6, 5, 4, 3, 2];
firstListItemMixinWithCodeDuplication.call(list_A_1);
firstListItemMixinWithCodeDuplication.call(list_A_2);
lastListItemMixinWithSharedReference.call(list_B_1);
lastListItemMixinWithSharedReference.call(list_B_2);
console.log('list_A_1.first() :', list_A_1.first());
console.log('list_A_2.first() :', list_A_2.first());
console.log('list_B_1.last() :', list_B_1.last());
console.log('list_B_2.last() :', list_B_2.last());
console.log('\n');
console.log('list_A_1.first :', list_A_1.first);
console.log('list_A_2.first :', list_A_2.first);
console.log(
'(list_A_1.first === list_A_2.first) ?',
(list_A_1.first === list_A_2.first),
'...applying closed code'
);
console.log('\n');
console.log('list_B_1.last :', list_B_1.last);
console.log('list_B_2.last :', list_B_2.last);
console.log(
'(list_B_1.last === list_B_2.last) ?',
(list_B_1.last === list_B_2.last),
'...applying shared code'
);
console.log('\n');
console.log(
'Object.getOwnPropertyNames(list_A_1) :',
Object.getOwnPropertyNames(list_A_1)
);/*
...
...
console.log(
'Object.getOwnPropertyNames(list_B_2) :',
Object.getOwnPropertyNames(list_B_2)
);*/
.as-console-wrapper min-height: 100%!important; top: 0;
【讨论】:
你确定 OP 是在谈论 mixin 组合吗? 说实话,不完全是。但我猜/认为 OP 想具体了解 inherited 和 own 属性。尤其是对于后者,了解应用/分配方法或任何组合粘合代码的实现可能会如何增加对象/实例的内存消耗可能会很有趣。 也许吧?对于一个不清楚的问题,我不会写这么长的答案。以上是关于组合与继承及其在 Javascript 中的成本的主要内容,如果未能解决你的问题,请参考以下文章