Javascript何时使用原型

我想了解什么时候适合在js中使用原型方法。 他们应该总是使用? 或者有没有使用它们的情况是不优选的和/或是否会导致性能损失?

在js中寻找常用的命名空间方法的网站上,大多数人使用非基于原型的实现:简单地使用一个对象或者一个函数对象来封装一个名字空间。

来自一个基于类的语言,很难不尝试和绘制相似之处,并认为原型就像“类”,我提到的名称空间实现就像静态方法。

原型是一个优化

使用它们的一个很好的例子就是jQuery库。 每当你通过使用$('.someClass')获得一个jQuery对象,那个对象就有几十个“方法”。 该库可以通过返回一个对象来实现:

 return { show: function() { ... }, hide: function() { ... }, css: function() { ... }, animate: function() { ... }, // etc... }; 

但是,这意味着内存中的每个jQuery对象都会有几十个包含相同方法的命名空间。

相反,这些方法是在一个原型上定义的,所有的jQuery对象都“inheritance”这个原型,以便以很less的运行时间获得所有这些方法。

jQuery如何正确的一个非常重要的部分是,这是程序员隐藏的。 这纯粹是一种优化,而不是你在使用库时必须担心的事情。

JavaScript的问题是,裸构造函数需要调用者记住用new前缀,否则他们通常不工作。 这没有什么好的理由。 jQuery通过在一个普通的函数$后面隐藏这个无意义来得到正确的结果,所以你不必关心对象是如何实现的。

所以你可以方便地用指定的原型创build一个对象,ECMAScript 5包含一个标准的函数Object.create 。 它的一个非常简化的版本将如下所示:

 Object.create = function(prototype) { var Type = function () {}; Type.prototype = prototype; return new Type(); }; 

它只是照顾编写构造函数的痛苦,然后用new调用它。

你什么时候会避免原型?

一个有用的比较是stream行的OO语言,如Java和C#。 这些支持两种inheritance:

  • 接口inheritance,在那里你implement一个interface ,使得类为接口的每个成员提供了自己独特的实现。
  • 实现inheritance,在这里extend一个提供某些方法的默认实现的class

在JavaScript中,原型inheritance是一种实现inheritance。 因此,在那些(在C#或Java中)你可以从基类派生出默认行为的情况下,你可以通过重写做一些小的修改,然后在JavaScript中,原型inheritance是有意义的。

但是,如果您处于以C#或Java方式使用接口的情况,那么在JavaScript中不需要任何特定的语言function。 没有必要显式声明表示接口的东西,也不需要将对象标记为“实现”该接口:

 var duck = { quack: function() { ... } }; duck.quack(); // we're satisfied it's a duck! 

换句话说,如果每个“types”的对象都有自己的“方法”的定义,那么从原型inheritance就没有价值。 之后,这取决于您为每种types分配了多less个实例。 但在许多模块化devise中,只有一个给定types的实例。

事实上, 有很多人提出实现inheritance是邪恶的 。 也就是说,如果一个types有一些共同的操作,那么如果它们没有被放到一个基类/超类中,或者只是作为普通的函数暴露在某个模块中,你想让他们操作。

如果你想声明对象的“非静态”方法,你应该使用原型。

 var myObject = function () { }; myObject.prototype.getA = function (){ alert("A"); }; myObject.getB = function (){ alert("B"); }; myObject.getB(); // This works fine myObject.getA(); // Error! var myPrototypeCopy = new myObject(); myPrototypeCopy.getA(); // This works, too. 

使用内置的prototype对象的一个​​原因是如果你将复制一个对象多次,将共享共同的function。 通过将方法附加到原型,可以节省每个new实例创build的重复方法。 但是当你把一个方法附加到prototype ,所有的实例都可以访问这些方法。

假设你有一个基类Car()类/对象。

 function Car() { // do some car stuff } 

那么你创build了多个Car()实例。

 var volvo = new Car(), saab = new Car(); 

现在,你知道每辆汽车将需要驾驶,打开等。而不是将方法直接附加到Car()类(每个创build的实例占用内存),您可以将方法附加到原型(创build方法只有一次),因此可以将这些方法同时用于新volvosaab

 // just mapping for less typing Car.fn = Car.prototype; Car.fn.drive = function () { console.log("they see me rollin'"); }; Car.fn.honk = function () { console.log("HONK!!!"); } volvo.honk(); // => HONK!!! saab.drive(); // => they see me rollin' 

当你要创build大量的特定types的对象的副本,并且他们都需要共享共同的行为时,将函数放在原型对象上。 通过这样做,每个函数只需要一个副本就可以节省一些内存,但这只是最简单的好处。

更改原型对象上的方法或添加方法会立即改变相应types的所有实例的性质。

现在到底为什么你要做所有这些事情主要是你自己的应用程序devise的function,以及你需要在客户端代码中做的事情。 (一个完全不同的故事将会是服务器内的代码;更容易想象在那里做更多的大规模的“OO”代码。)

如果我在基于类的术语解释那么Person是类,walk()是Prototype方法。 所以walk()只有在你用这个实例化新对象之后才会有它的存在。

所以,如果你想创build像Person这样的对象的副本,你可以创build许多用户。Prototype是一个很好的解决scheme,因为它通过为内存中的每个对象共享/inheritance相同的函数副本来节省内存。

静态在这种情况下不是很有帮助。

 function Person(){ this.name = "anonymous"; } // its instance method and can access objects data data Person.prototype.walk = function(){ alert("person has started walking."); } // its like static method Person.ProcessPerson = function(Person p){ alert("Persons name is = " + p.name); } var userOne = new Person(); var userTwo = new Person(); //Call instance methods userOne.walk(); //Call static methods Person.ProcessPerson(userTwo); 

所以这更像是实例方法。 该对象的方法就像静态方法。

https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript