使用对象组合的多态性 - JavaScript



多态性只适用于JavaScript中的OOP概念吗?我正在尝试在 JavaScript 中使用对象组合与原型/类继承。如果这个概念适用,在对象组合中实现多态性会是什么?

下面是实现多态性的原型继承示例(方法重写,在子对象重新实现render方法(

function HtmlElement() { 
this.click = function() { 
console.log('clicked');
}
}
HtmlElement.prototype.focus = function(){
console.log('focued');
}
function HtmlSelectElement(items = []) { 
this.items = items;
this.addItem = function(item) { 
this.items.push(item);
}
this.removeItem = function(item) {
this.items.splice(this.items.indexOf(item), 1);
}
this.render = function() {
return `
<select>${this.items.map(item => `
<option>${item}</option>`).join('')}
</select>`;
}  
}
HtmlSelectElement.prototype = new HtmlElement(); 
HtmlSelectElement.prototype.constructor = HtmlSelectElement;
function HtmlImageElement(src) { 
this.src = src; 
this.render = function() {
return `<img src="${this.src}" />`
}
}
HtmlImageElement.prototype = new HtmlElement(); 
HtmlImageElement.prototype.constructor = HtmlImageElement;
const elements = [
new HtmlSelectElement([1, 2, 3]),
new HtmlImageElement('http://')
];
for (let element of elements) 
console.log(element.render());

实际上很难在JavaScript中谈论多态性,因为维基百科将多态性定义为:

多态性[...]是为不同类型的实体提供单个接口[1]或使用单个符号来表示多个不同类型的实体。[2]

由于只有基元类型和"对象",因此很难谈论这些对象的类型。由于原型链和instanceof运算符,可以说还有其他类型,也可以说javascript有鸭子类型。举个例子:

class User {
constructor() { this.name = "test"; }
}
value             |  type      |    instanceof User  | "name" in 
-----------------------------------------------------------------------------------
new User()        |  object    |     true            | true
{ name: "test" }  |  object    |     false           | true
{}                |  object    |     false           | false

现在哪一个是用户类型?是否有用户类型?没有对错,只有意见。以下是我对此的看法:

多态性仅适用于 JavaScript 中的 OOP 概念吗?

我会说不。范式是"写某些东西的风格",多态性是描述对象关系的一种方式,你可以在所有范式中使用对象。

如果这个概念适用,在对象组合中实现多态性会是什么?

如果我们有两个工厂,假设userreader它们看起来像:

function createUser() {
return { name: "test" };
}
function createReader() {
return { books: ["a book"] };
}
const user = createUser(), reader = createReader();

现在,我们可以通过多种方式获得多态性:

1(行多态性

1a(我们可以通过添加书籍将用户变成读者:

user.books = ["another book"];

现在用户读者,因为它有(这是鸭子测试(

1b( 我们可以将用户和读者结合起来:

const readingUser = Object.assign(createUser(), createReader());

2( 子类型

如果我们将构造函数更改为:

function createReader() {
return { ...createUser(), books: ["a book"] };
}

现在每个读者都是用户,我们得到了继承(但没有经典继承(。

3(特设多态性

我们可以声明对用户或读者行为不同的函数:

function doSomething(obj) {
if(obj.name) {
console.log("a user");
}
if(obj.books) {
console.log("a reader");
}
}
doSomething(user); // a user
doSomething(reader) // a reader
doSomething(readingUser); // a user, a reader

4(参数多态性

读者和用户都是对象,因此我们可以将它们"作为对象"处理:

Object.freeze(reader);
Object.freeze(user);