组合与继承及其在 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 想具体了解 inheritedown 属性。尤其是对于后者,了解应用/分配方法或任何组合粘合代码的实现可能会如何增加对象/实例的内存消耗可能会很有趣。 也许吧?对于一个不清楚的问题,我不会写这么长的答案。

以上是关于组合与继承及其在 Javascript 中的成本的主要内容,如果未能解决你的问题,请参考以下文章

类的继承与组合

javascript 组合模式,对象冒充+原形链继承

Javascript继承6:终极继承者----寄生组合式继承

扫盲-继承与组合

JavaScript继承的实现

JavaScript继承的实现