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

关于如何在JavaScript中创建类的困惑,javascript,class,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

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

我希望有人能启发我。

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

  • 包装在自调用函数中(
    (function(){…})(;
  • 使用
    上的
    .prototype
    属性。
    获取方法
  • 将内容包装到自调用函数中,然后将结果(如
    return
    语句中定义的)分配给变量称为。这是一种常见的模式,用于确保范围更受控制

    使用
    Dog.prototype.sound=function(){}
    this.sound=function(){/code>更可取。区别在于
    Dog.prototype.sound
    是使用
    Dog
    构造函数和
    this.sound=function(){}为所有对象定义一次的
    将为创建的每个Dog对象再次定义


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

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

    在第二段代码中,您展示的只是额外包装在IIFE中,这在本例中没有多大作用。

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

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


    正如您所看到的,它们都有相同的结果。其他人已经讨论了
    原型
    ,所以我在这里不提它。

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

    原型

    Javascript继承是造成混淆的一个原因,但它实际上相当简单:每个对象都有一个原型,当我们试图访问不在原始对象上的属性时,我们将检查这个原型。原型本身将有一个原型;在一个简单的情况下,如
    Dog
    ,这可能是
    对象。原型

    在您的两个示例中,由于
    new
    的作用,我们最终会得到一个原型链,它看起来是这样的:
    fido->Dog.prototype->Object.prototype
    。因此,如果我们试图在fido上查找
    name
    属性,我们会在对象上找到它。另一方面,如果我们查找
    hasOwnProperty属性,我们将无法在Fido上找到它,无法在
    Dog.prototype
    上找到它,然后到达
    Object.prototype
    ,我们将在那里找到它

    声音
    的情况下,您的示例在两个不同的位置定义它:在第一种情况下,
    fido
    ,我们创建的其他每只狗都有自己的函数副本。在第二种情况下,
    dog.prototype
    将有一个函数副本,当调用该方法时,单个狗将访问该函数ed.这避免了在存储
    声音
    功能的副本时浪费资源


    这还意味着我们可以扩展原型链;也许我们需要一个继承
    Dog
    sound
    函数的
    Corgi
    类。在第二种情况下,我们可以简单地确保
    Dog.prototype
    位于
    Corgi.prototype
    的原型链中;在第一种情况下,我们需要创建一个实际的Dog和把它放在原型链中。

    结果有一点不同。第二个例子可以被认为是更好的,因为使用了
    prototype
    。不,不是我。喜欢用户名:)第二个不是暴露的模块模式,也不是任何模块模式。这只是在生活中设置一个原型方法。要区分模块模式的不同实现,请参阅关于如何使用构造函数和原型的更多信息,可以在这里找到:希望有帮助