很长一段时间以来,我一直通过执行以下操作来编写 JavaScript 类
function MyClass(){
this.v1;
this.foo = function(){
return true;
}
};
然后我发现了 TypeScript,看起来它会将其类编译为
var MyClass = (function () {
function MyClass(message) {
this.v1 = message;
}
MyClass.prototype.foo = function () {
return "Hello, " + this.v1;
};
return MyClass;
})();
我在网上找到的另一种方法是
var MyClass = {
v1:1,
foo: function(){
return true;
}
};
这对我来说看起来很难看,但也许我错过了这种方法的一些好处,因为它看起来是网络上大多数人在 javaScript 中处理对象的方式。
我能够从我创建的函数中继承的第一种方法。
Function.prototype.extends = function(parent){
this.prototype = new parent();
this.prototype.constructor = this;
};
我还看到了许多其他在 JavaScript 中创建类的方法。我想知道我的方法是否错误或者是否有进行OOP的最佳实践方法。我完成的所有项目都使用第一个示例。您可以在https://github.com/Patrick-W-McMahon上看到现在我了解了 JavaScript 编译器正在做什么,我开始质疑我的方法。我想知道其他 JavaScript 程序员建议的最佳方法是什么,以及这些方法之间是否存在差异。我有 C++/Java 背景,因此我编写 JavaScript 来匹配我的背景。
最佳答案
您在这里读到的内容称为幂构造函数,更多相关信息请参见:
Douglas Crockford about Inheritance
<小时/>作为一种多范式语言,JavaScript 非常适合这些不同的考虑。事实是,它以您想象的方式在您的大脑中成型。
换句话说,如果您可以用一种方式推理您的结构,那么就以这种方式使用它。
另一方面,如果您希望完全“摆脱”自己的约束,那么您应该完全放弃类中的推理,并拥抱原型(prototype)继承,而不使用任何类似于类的事物全部。鸭子类型是一个自然的结果,在极端情况下,你会在整个地方使用闭包。
我经常做的是这样的:
function myItemBuilder(p1)
{
var s0, p0 = 0;
// s0 is a shared private property (much like static in classes)
// p0 is a shared private property but will be factorized (rendered non-shared)
// p1 is a private instance property
return (function (p0) { // factorize p0 if necessary
return {
publicProperty : 3,
method1 : function (arg1) {
// code here (may use publicProperty, arg1, s0, p0 (factorized) and p1)
},
method2 : function (arg2) {
// code here (may use publicProperty, arg2, s0, p0 (factorized) and p1)
}
};
}(p0++)); // on each invocation p0 will be different and method1/method2 will not interfere across invocations (while s0 is shared across invocations)
}
编辑:仅当您需要分解 p0 时才需要内部闭包(即每次调用时 p0 都有单独的独立值)。当然,如果不需要 p0 分解,请省略内部闭包。
The above example is intentionally more complex than required to illustrate various interesting cases.
调用像 myItemBuilder("hello")
这样的方法会构建一个具有这些特定功能的新项目,但实际上没有 class
构造本身.
当您想要放弃经典继承时,这是获取实例的一种特别强大的方法。例如,在 C++ 中,您可以从多个类继承,这称为混合。在 Java 和 C# 中,您只有单继承,但接口(interface)可以为您提供帮助。
这里,我上面展示的是装配线比喻,它可以将组件组装到实例中,结果是没有具体 (1)类、接口(interface)和混合之间的区别。它们都只是具有您可以通过元编程(鸭子类型、反射/检查)进行反射(reflection)的功能的实例。仍然存在逻辑 (2) 差异,因为:(1) 具体实例的行为相同,独立于它们的存在方式,但 (2) 从逻辑上讲,接口(interface)是契约,而实例是实现。
如果你真的懂SOLID和 Assembly Line Metaphor这一切都是有道理的。否则我请您原谅这么长的答案:)
添加:
使用这种方法,您无法检查类型,但您也不需要这样做,因为鸭子类型允许您找到所需的方法,而无需查看类或接口(interface)契约。这类似于将每个方法放在单独的单一方法接口(interface)中。
关于javascript 不同的 OOP 方法标准,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25003167/