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

时间:2018-10-10 08:32:12

标签: 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());

1 个答案:

答案 0 :(得分:2)

实际上很难谈论JavaScript中的多态性,因为Wikipedia defines polymorphism as:

  

多态[...]是为不同类型的实体提供单个接口[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"];

现在 user 阅读器,因为它具有 books (即Duck test

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);