【问题标题】:JavaScript inheritance through a call to the ancestor function通过调用祖先函数的 JavaScript 继承
【发布时间】:2013-09-01 12:11:44
【问题描述】:

我正在尝试(对我而言)一种新的继承类型。我想用一个决定返回哪个继承对象的参数调用继承函数。

这里有一个例子来说明我的意思:

function Localizor(type) {
  this.language = "English"
  this.endonym = "English"

  if (window[type]) {
    return new window[type]()
  }
}
Localizor.prototype.native = function native() {
  return "I speak " + this.endonym
}
Localizor.prototype.english = function () {
  return "I speak " + this.language
}


function French () {
  this.language = "French";  
  this.endonym = "français"
}
French.prototype = new Localizor()
French.prototype.native = function french() {
  return "Je parle " + this.endonym
}


function Thai () {
  this.language = "Thai";  
  this.endonym = "ไทย"
}
Thai.prototype = new Localizor()
Thai.prototype.native = function thai() {
  return "พูดภาษา" + this.endonym
}

如果我在没有参数(或无效参数)的情况下调用new Localizor(),我会得到一个简单的英语对象。如果我用“法语”或“泰语”的参数调用它,我会得到一个对象,其中继承者覆盖了一些继承的方法,因此它说法语或泰语。例如:

var thai = new Localizor("Thai")
var feedback = thai.language + " | " + thai.endonym + " | " + thai.english() + " | " + thai.native()  
console.log(feedback)

这给了我输出Thai | ไทย | I speak Thai | พูดภาษาไทย

我有三个问题:
1. 这种类型的继承是否已经记录在某处(是否有名称)?
2. 这样工作有什么危险吗?
3. 这个例子检查window[type] 的存在,这在浏览器中工作时很好。如果这是在 node.js 的模块中,是否有等效的方法来确定模块中是否存在函数?

编辑以响应 Zero21xxx

这是我发现的一种检测模块中是否存在构造函数的方法,但对我来说,这看起来很危险。它有什么风险?有什么更好的方法?

function extend(Child, Parent) {
  function F() {}
  F.prototype = Parent.prototype
  Child.prototype = new F()
  //Child.prototype.constructor = Child
  Child.parent = Parent.prototype
}

function Localizor(type) {
  this.language = "English"
  this.endonym = "English"

  this.French = function français () {
    this.language = "French";  
    this.endonym = "français"
  }
  extend(this.French, this)
  this.French.prototype.native = function french() {
    return "Je parle " + this.endonym
  }

  this.Thai = function ไทย () {
    this.language = "Thai";  
    this.endonym = "ไทย"
  }
  extend(this.Thai, this)
  this.Thai.prototype.native = function thai() {
    return "พูดภาษา" + this.endonym
  }

  if (typeof this[type] === "function") {
   return new this[type]()
  }
}
Localizor.prototype.native = function native() {
  return "I speak " + this.endonym
}
Localizor.prototype.english = function () {
  return "I speak " + this.language
}

module.exports = Localizor

【问题讨论】:

  • 似乎是工厂模式的一个很好的用例。 Localizer.create('French').

标签: javascript node.js inheritance


【解决方案1】:

以我的拙见,您应该为EnglishFrenchThai 拥有三个独立的构造函数,它们继承自一个通用构造函数(我们称之为Locale)。如下所示:

function Locale(constructor, language, endonym, native) {
    this.constructor = constructor;
    this.language = language;
    this.endonym = endonym;

    this.native = function () {
        return native + this.endonym;
    };
}

Locale.prototype.english = function () {
    return "I speak " + this.language;
};

function English() {}
function French() {}
function Thai() {}

English.prototype = new Locale(English, "English", "English", "I speak ");
French.prototype = new Locale(French, "French", "français", "Je parle ");
Thai.prototype = new Locale(Thai, "Thai", "ไทย", "พูดภาษา");

这导致separation of concerns:每个构造函数都只精确地执行它的预期用途。不多也不少。现在您可以创建一个localizer 函数,如下所示:

function localizer(language) {
    switch (language) {
    case "French": return new French;
    case "Thai": return new Thai;
    default: return new English;
    }
}

因此,您只需拨打localizer 即可获得所需的Locale

【讨论】:

  • 这很有道理,谢谢。 (我还不能投票赞成你的答案,因为我没有足够的声誉:) 'this.constructor = constructor' 技术对我来说是新的。
【解决方案2】:
  1. 是的,这是人们经常尝试以不同程度成功实现的“伪经典”继承。查看this
  2. 嗯,你现在的方式有点难以阅读。您编写的代码说创建一个Localizor 对象,但您会得到一个Thai 对象。这可能很难追踪错误。
  3. 是的,有一些方法可以检查这些内容,这实际上取决于您如何构建模块。

我的建议是稍微改写一下

function Localizor(language, endonym) {
  this.language = language;
  this.endonym = endonym;
}
Localizor.prototype.native = function native() {
  return "I speak " + this.endonym;
};
Localizor.prototype.english = function () {
  return "I speak " + this.language;
};


function French (language, endonym) {
  Localizor.apply(this, arguments);
}
French.prototype = new Localizor();
French.prototype.native = function french() {
  return "Je parle " + this.endonym;
};


function Thai (language, endonym) {
  Localizor.apply(this, arguments);
}
Thai.prototype = new Localizor();
Thai.prototype.native = function thai() {
  return "พูดภาษา" + this.endonym;
};

这样,您可以调用正确的构造函数并取回相应的对象。您还可以调用“基类”构造函数并附加languageendonym 属性,而无需复制和粘贴该代码。您也不需要像当前所做的那样检查类型,因为您正在声明它们您希望它们如何工作。最后,如果你愿意,你可以让你的Localizor 函数接受第三个参数,那就是字符串“I Speak”或其他任何东西,这样你就不需要多个对象了。

Here 是一个你可以玩弄的游乐场。

服务器端或客户端,我认为这是一个更好的方法。

【讨论】:

  • 非常感谢您的周到意见。我(相信我)理解伪经典继承,但我尝试的是不同的东西,可能更接近寄生继承,但可以选择寄生。我想避免直接调用泰语或法语,以便我可以使用字符串变量来指示我想要返回哪个对象,具体取决于第三方输入。至于问题 3,您能否提出一种构建模块的方法,以便我可以检查给定构造函数是否存在?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-07
  • 2012-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-29
相关资源
最近更新 更多