【问题标题】:Confusion about how to create classes in JavaScript关于如何在 JavaScript 中创建类的困惑
【发布时间】:2015-03-24 13:49:35
【问题描述】:

过去在 JavaScript 中创建“类”时,我是这样做的:

function Dog(name){
    this.name=name;
    this.sound = function(){
        return "Wuf";
    };
}

但是,我只是看到有人这样做:

var Dog = (function () {
    function Dog(name) {
        this.name = name;
    }
    Dog.prototype.sound = function () {
        return "Wuf";
    };
    return Dog;
})();

你能做到这两种方式,还是我做错了?在那种情况下,为什么?就我们最终得到的结果而言,两者之间到底有什么区别?在这两种情况下,我们都可以通过以下方式创建对象:

var fido = new Dog("Fido");
fido.sound();

希望有人能赐教。

【问题讨论】:

标签: javascript class


【解决方案1】:

你的方式和他们的方式有两个重要的区别。

  1. 包装自调用函数 ((function() { ... })();)
  2. 对方法使用 .prototype 属性而不是 this.

将事物包装在自调用函数中,然后将结果分配(如在 return 语句中定义的变量被称为 module pattern。这是确保范围得到更多控制的常见模式。

使用Dog.prototype.sound = function() {}this.sound = function()更可取。不同之处在于Dog.prototype.sound 为所有具有Dog 构造函数的对象定义一次,而this.sound = function() {} 为每个创建的Dog 对象再次定义

经验法则是:对一个对象来说是个体的东西(通常是它的属性)将在this 上定义,而对同一类型的所有对象(通常是函数)共享的东西将被定义在原型上。

【讨论】:

    【解决方案2】:

    使用您的代码,您将为正在创建的每个新 Dog 实例创建一个新函数 sound。 Javascript 的prototype 通过只创建一个所有对象实例共享的函数来避免这种情况;基本上是经典继承。

    在您展示的第二个代码中,它只是另外包装在 IIFE 中,在这种情况下并没有多大作用。

    【讨论】:

      【解决方案3】:

      第一种是传统的创建构造函数的方法。第二个是立即调用的函数表达式,它返回一个构造函数。此方法允许您将变量保留在模块中,而不会泄漏到可能成为问题的全局范围内。

      就我们最终得到的结果而言,两者之间到底有什么区别?

      正如您所见,它们都具有相同的结果。其他人都讲过prototype,这里就不提了。

      【讨论】:

      • 结果略有不同。由于使用了prototype,第二个例子可以认为更好。
      • 不,不是我。
      • 爱这个用户名:)
      • 第二个不是揭示模块模式,也不是任何模块模式。它只是在 IIFE 中设置原型方法。要区分模块模式的不同实现,请参阅stackoverflow.com/questions/22906662/…
      【解决方案4】:

      第二种更好,因为它利用了 Javascript 的原型继承机制。

      原型

      Javascript 继承是一个令人困惑的原因,但它实际上相当简单:每个对象都有一个原型,当我们尝试访问不在原始对象上的属性时,我们将检查这个对象。原型本身将有一个原型;在一个简单的例子中,比如Dog,这可能是Object.prototype

      在您的两个示例中,由于 new operator works 的方式,我们最终会得到一个如下所示的原型链:fido->Dog.prototype->Object.prototype。因此,如果我们尝试在 Fido 上查找 name 属性,我们会在对象上找到它。另一方面,如果我们查找 hasOwnProperty 属性,我们将无法在 Fido 上找到它,无法在 Dog.prototype 上找到它,然后到达 Object.prototype,我们将在其中找到它。

      sound 的情况下,您的示例在两个不同的地方定义它:在第一种情况下,fido 和我们创建的所有其他狗都将拥有自己的函数副本。在第二种情况下,Dog.prototype 将拥有该函数的单个副本,当调用该方法时,各个狗将访问该副本。这样可以避免在存储 sound 函数的副本时浪费资源。

      这也意味着我们可以扩展原型链;也许我们想要一个从Dog 继承sound 函数的Corgi 类。第二种情况,我们可以简单的保证Dog.prototypeCorgi.prototype的原型链中;首先,我们需要创建一个实际的 Dog 并将其放入原型链中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-14
        • 1970-01-01
        • 2014-03-21
        相关资源
        最近更新 更多