【问题标题】:javascript different OOP methods standardsjavascript不同的OOP方法标准
【发布时间】:2014-07-28 19:49:20
【问题描述】:

很长时间以来,我一直在通过执行以下操作来编写 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 以匹配我的背景。

【问题讨论】:

  • 在 js 中有上百万种不同的方式来做“OOP”;都有一些小的优点和缺点,但这些差异很少会叠加起来以做出“正确”或“错误”的事情。你的代码可能更像是 Brendan 的想法,而不是 typescript 的版本。
  • 两者都应该工作,但使用prototype 更标准。
  • 第一个例子你不能实现继承或多态。例如,由 new(MyClass) 创建的所有对象都将从 object 继承,仅此而已。
  • 拥有 this.foo() 和 this.prototype.foo() 会有什么不同

标签: javascript class oop methods


【解决方案1】:

您在此处阅读的内容称为 power 构造函数,更多信息请参见此处:

Douglas Crockford about Inheritance


作为一种多范式语言,JavaScript 非常适合这些不同的考虑。事实上,它塑造你的大脑,就像你想象的那样。

换句话说,如果你可以用一种方式来推理你的结构,那就用那种方式吧。

另一方面,如果您想完全“摆脱”自己的约束,那么您应该完全放弃类中的推理,并接受原型继承,而无需任何类似于类的事物全部。鸭子类型是一个自然的结果,在极端情况下,你会在所有地方使用闭包。

我经常做的是这样的:

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 分解,请忽略内部闭包。

为了说明各种有趣的案例,上面的示例故意比所需的更复杂。

myItemBuilder("hello") 这样调用这个方法会构建一个具有这些特定功能的新项目,但实际上并没有class 构造本身

当您想放弃经典继承时,这是一种特别强大的获取实例的方法。例如,在 C++ 中,您可以从多个类继承,这称为混合。在 Java 和 C# 中,您只有单一继承,但接口可以帮助您。

这里,我上面展示的是装配线比喻,它可以将组件组装成一个实例,结果没有具体 (1)类,接口和混合之间的区别。它们都是具有特性的实例,您可以通过元编程(鸭子类型、反射/检查)进行反思。仍然存在 逻辑上的 (2) 区别在于:(1) 具体实例的行为相同,与它们形成的方式无关,但是 (2) 从逻辑上讲,接口是契约,而实例是实施。

如果您真的了解SOLIDAssembly Line Metaphor,那么所有这些都是有道理的。否则我请你原谅这个冗长的答案:)

添加:

使用这种方法,您无法检查类型,但您不需要检查,因为鸭子类型允许您找到所需的方法,而无需查看类或接口协定。这类似于将每个方法放在单独的单方法接口中。

【讨论】:

  • 考虑这样的对象需要一些时间。我将审查这篇文章,看看我是否完全掌握它。这很像java工厂吗?
  • Concrete FactoryAbstract Factory 是创造性的 GoF 模式。我猜 java factory 是这两者之一的实现。流水线隐喻非常相似,但它不只是一种模式,它是原型继承范式的一部分。如果所有这些都没有意义,不要害怕,按照你知道的方式使用 JS,因为最重要的是你理解并能够维护自己的代码。如果你不知道自己在做什么,没人会这样做:)
  • 什么是}(p1));在函数的末尾做什么?该函数以 (p1) 开头。但我不知道最后那个在做什么。
  • 它调用刚刚定义的函数。真名是Closure function (x) { /*do smthg*/}(3);。这将调用匿名function 传递3 为参数x。由于它是匿名的,因此您无法在其他任何地方调用它。
  • 所以它很像 java 的方式 foo(x=3){/*do smthg */} 这是一个正确的假设吗?
【解决方案2】:

这里有解释

http://www.2ality.com/2011/06/coffeescript-classes.html

一个普通的 JavaScript 类定义,包装在一个 IIFE [3] 中。在这里使用 IIFE 没有任何好处,除了有一个单一的赋值(这在对象字面量中很重要,但在这里不重要)。

【讨论】:

    【解决方案3】:

    这是个人喜好问题。使用这种方法

    var MyClass = {
        v1:1,
        foo: function(){
           return true;
        }
    };
    

    导致字符更少,因此 JS 文件更小,所以这是我通常使用的方法,但没有错误或正确的方法。顺便提一句。既然您评论说这种对象构造很丑陋,您可能想坚持您习惯的方式。但是,如果您喜欢冒险check out this project

    它使 javascript 中的 oop 变得快速、轻松且不那么难看。另外,它正确支持多重继承。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-07
      • 1970-01-01
      • 2013-02-03
      • 2016-06-19
      • 1970-01-01
      • 2012-05-17
      • 1970-01-01
      相关资源
      最近更新 更多