gpt4 book ai didi

javascript - JavaScript 中的组合、继承和聚合

转载 作者:IT王子 更新时间:2023-10-29 02:56:21 24 4
gpt4 key购买 nike

网上有很多关于组合与继承的信息,但我还没有找到像 JavaScript 的例子。使用下面的代码来演示继承:

function Stock( /* object with stock names and prices */ ) {
for (var company_name in arguments[0]) {
// copy the passed object into the new object created by the constructor
this[company_name] = arguments[0][company_name];
}
}

// example methods in prototype, their implementation is probably redundant for
// this question, but list() returns an array with toString() invoked; total()
// adds up the stock prices and returns them. Using ES5 feature to make
// inherited properties non-enumerable

Stock.prototype = {
list: function () {
var company_list = [];
for (var company_name in this)
company_list.push(company_name);
return company_list.toString();
},
total: function () {
var price_total = 0;
for (var company_name in this)
price_total += this[company_name];
return '$' + price_total;
}
};

Object.defineProperties(Stock.prototype, {
list: { enumerable: false },
total: { enumerable:false }
});

var portfolio = new Stock({ MSFT: 25.96, YHOO: 16.13, AMZN: 173.10 });
portfolio.list(); // MSFT,YHOO,AMZN
portfolio.total(); // $215.19

(为了使代码更小,您可以省略方法实现,例如: Stock.total = function(){ /* code */ } 我只是把它们放在那里是为了花哨)。如果 OOP 中的很多情况都喜欢组合,为什么大多数使用 JavaScript 的人似乎只使用原型(prototype)和继承?我在网上没有找到很多关于 JavaScript 组合的信息,只有在其他语言中。

有人可以给我一个使用上述代码的示例来演示组合和聚合吗?

最佳答案

在处理组合与继承时,语言无关紧要。如果您了解什么是类以及类的实例是什么,那么您就拥有了所需的一切。

组合只是当一个类由其他类组成时;或者换一种说法,一个对象的实例引用了其他对象的实例。

继承是指一个类从另一个类继承方法和属性。

假设您有两个功能 A 和 B。您想定义第三个功能 C,它具有 A 和 B 的部分或全部。您可以使 C 从 B 和 A 扩展,在这种情况下,C 拥有 B 的所有内容A 有因为 C isA B 和 A,或者您可以使 C 的每个实例具有 A 的实例和 B 的实例,并调用这些功能上的项。在后一种情况下,每个实例 C 实际上都包含一个 B 的实例和一个 A 的实例。

当然,根据语言,您可能无法从 2 个类扩展一个类(例如 Java 不支持多重继承),但这是与该概念无关的语言特定细节。

现在,对于语言特定的细节......

我使用了类这个词,但 javascript 没有类的概念。它有对象,仅此而已(简单类型除外)。 Javascript 使用原型(prototype)继承,这意味着它有一种有效定义对象和这些对象上的方法的方法(这是另一个问题的主题;您可以搜索 SO,因为已经有答案。)

所以继续我们上面的例子,你有 A、B 和 C。

对于继承,你会有

// define an object (which can be viewed as a "class")
function A(){}

// define some functionality
A.prototype.someMethod = function(){}

如果你想让 C 扩展 A,你会这样做
C.prototype = new A();
C.prototype.constructor = A;

现在每个 C 实例都有方法 someMethod ,因为 C 的每个实例“都是 A”A。

Javascript 没有多重继承*(稍后会详细介绍),因此您不能让 C 扩展 A 和 B。但是,您可以使用组合来赋予它功能。事实上,这就是一些人更喜欢组合而不是继承的原因之一。组合功能没有限制(但这不是唯一的原因)。
function C(){
this.a = new A();
this.b = new B();
}

// someMethod on C invokes the someMethod on B.
C.someMethod = function(){
this.a.someMethod()
}

因此,这里有关于继承和组合的简单示例。然而,这并不是故事的结局。我之前说过Javascript不支持多重继承,从某种意义上说它不支持,因为你不能将一个对象的原型(prototype)建立在多个对象的原型(prototype)之上;即你不能做
C.prototype = new B();
C.prototype.constructor = B;
C.prototype.constructor = A;

因为一旦你做了第三行,你就取消了第二行。这对 instanceof 有影响运算符(operator)。

但是,这并不重要,因为仅仅因为您不能两次重新定义对象的构造函数,您仍然可以向对象的原型(prototype)添加任何您想要的方法。所以仅仅因为你不能做上面的例子,你仍然可以在C.prototype中添加任何你想要的东西,包括A和B的原型(prototype)上的所有方法。

许多框架都支持这一点并使其变得容易。我做了很多 Sproutcore 的工作;使用该框架,您可以做到
A = {
method1: function(){}
}

B = {
method2: function(){}
}

C = SC.Object.extend(A, B, {
method3: function(){}
}

在这里,我在对象字面量中定义了功能 AB ,然后将两者的功能添加到 C ,所以 C 的每个实例都有方法 1、2 和 3。在这种特殊情况下, extend方法(由框架提供)完成设置对象原型(prototype)的所有繁重工作。

编辑 - 在您的评论中,您提出了一个很好的问题,即“如果您使用组合,您如何协调主对象的范围与组成主对象的对象的范围”。

有很多方法。第一个是简单地传递参数。所以
C.someMethod = function(){
this.a.someMethod(arg1, arg2...);
}

在这里,您并没有弄乱作用域,您只是在传递参数。这是一种简单且非常可行的方法。 (参数可以来自 this 或传入,无论如何......)

另一种方法是使用 call (或 apply )javascript 方法,基本上允许您设置函数的范围。
C.someMethod = function(){
this.a.someMethod.call(this, arg1, arg2...);
}

更清楚一点,以下是等效的
C.someMethod = function(){
var someMethodOnA = this.a.someMethod;
someMethodOnA.call(this, arg1, arg2...);
}

在 javascript 中,函数是对象,因此您可以将它们分配给变量。
call这里的调用是设置 someMethodOnA 的范围至 this ,这是 C 的实例。

关于javascript - JavaScript 中的组合、继承和聚合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8696695/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com