关于如何在JavaScript中创建类的困惑
在过去用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
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
。不,不是我。喜欢用户名:)第二个不是暴露的模块模式,也不是任何模块模式。这只是在生活中设置一个原型方法。要区分模块模式的不同实现,请参阅关于如何使用构造函数和原型的更多信息,可以在这里找到:希望有帮助