首页 > 解决方案 > 一个关于实现接口及其继承的javascript构造函数问题

问题描述

使用 javascript 实现接口及其继承时遇到问题。

内容和思路来自《Learning JavaScript Design Pattern》一书。我尝试使用它的接口代码,并希望我使用的方式可以使它像 C# 一样。我使用的代码如下:

var Interface = function(name, methods) {
  if (arguments.length != 2) {
    throw new Error("Interface constructor called with " + arguments.length +
      "arguments, but expected exactly 2.");
  }

  this.name = name;
  this.methods = [];
  for (var i = 0, len = methods.length; i < len; i++) {
    if (typeof methods[i] !== 'string') {
      throw new Error("Interface constructor expects method names to be " +
        "passed in as a string.");
    }
    this.methods.push(methods[i]);
  }
};


function extend(subClass, superClass) {
  var F = function() {};
  F.prototype = superClass.prototype;
  subClass.prototype = new F();
  console.log(subClass.name);
  console.info(subClass);
  subClass.prototype.constructor = subClass;

  subClass.superclass = superClass.prototype;
  if (superClass.prototype.constructor == Object.prototype.constructor) {
    superClass.prototype.constructor = superClass;
  }
}

var Composite = new Interface('Composite', ['add', 'remove', 'getChild']);

console.log(Composite.name);
console.info(Composite);
console.log(Composite.__proto__.constructor.name);

var testinterface = function(name ,methods) {
  Composite.call(this, name, methods);
};

extend(testinterface, Composite);

但是在执行代码时,错误消息显示:无法读取未定义的属性“构造函数”。
当我声明函数testinterface时确实有问题,但我不知道为什么,因为在extend的函数体中,console.log输出说明testinterface仍然是一个函数声明,没有任何原型,甚至是构造函数。
有什么办法可以纠正这个问题,为什么代码不起作用。任何指示都非常感谢,非常感谢。

标签: javascript

解决方案


I see a post about polymorphism, https://medium.com/yld-blog/program-like-proteus-a-beginners-guide-to-polymorphism-in-javascript-867bea7c8be2 . I modify some codes from this web page, the codes can run, and its code snippet is as following:

function identical(a, b) {
  return a === b;
}

class Protocol {
  // accept a list of method-names
  constructor(...methods) {
    this.implementations = {};
    // and create a method for each
    methods.forEach(method => {
      // that will dispatch to an implementation stored on the type of the first argument
      this[method] = (type, ...args) => {
        // with the convention that an object's type is given by its constructor
        return this.implementations[type.constructor][method](type, ...args);
      }
    });
  }
  // register implementations for a type
  extendTo(typeConstructor, implementation) {
    const typed = this.implementations[typeConstructor] = {};
    Object.keys(implementation)
      .forEach(method => {
        typed[method] = implementation[method];
      });
  }
}

const Ramda = new Protocol('equals', 'map', 'add'); /* and the rest! */
Ramda.extendTo(String, {
  equals: (a, b) => a === b,
  map: (a, f) => a.split('').map(f),
  add: (a, b) => a + b
})

Ramda.extendTo(Date, {
  equals: (a, b) => identical(a.valueOf(), b.valueOf()),
  add: (a, b) => new Date(Number(a) + Number(b))
  // map not implemented
})

console.log(Ramda.equals('hello', 'world')); // false
console.log(Ramda.equals(new Date(1), new Date(1))); // true

I think, if I can combine these concepts, the javescript interface may be implemented.


推荐阅读