关于如何在JavaScript中创建类的困惑

时间:2015-03-24 13:49:36

标签: javascript class

过去在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();

我希望有人能够启发我。

4 个答案:

答案 0 :(得分:15)

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

  1. 包装自我调用函数((function() { ... })();
  2. 使用.prototype属性而非this.方法。
  3. 在自调用函数中包装事物,然后将结果(如return语句中定义的那样分配给变量称为module pattern。它是确保范围更广泛的常见模式控制。

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

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

答案 1 :(得分:4)

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

在第二个代码中,您显示的是另外包含在IIFE中,在这种情况下,它并没有做太多。

答案 2 :(得分:3)

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

  

两者在我们最终的结果方面究竟有什么不同?

正如您所见,他们都有相同的结果。其他人已经谈过prototype所以我不会在这里提到它。

答案 3 :(得分:2)

第二个是优选的,因为它利用了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函数的重复项时浪费资源。

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

相关问题