Answers:
原型是一种优化。
很好地使用它们的一个很好的例子是jQuery库。每次使用来获取jQuery对象时$('.someClass')
,该对象都有数十种“方法”。该库可以通过返回一个对象来实现:
return {
show: function() { ... },
hide: function() { ... },
css: function() { ... },
animate: function() { ... },
// etc...
};
但这意味着内存中的每个jQuery对象都会有数十个包含相同方法的命名槽,一遍又一遍。
相反,这些方法在原型上定义,并且所有jQuery对象都“继承”该原型,以便以很少的运行时成本获得所有这些方法。
jQuery如何正确实现的一个至关重要的部分是它对程序员是隐藏的。它纯粹是一种优化,而不是您使用库时要担心的事情。
JavaScript的问题在于,裸露的构造函数要求调用者记住给它们加上前缀,new
否则它们通常将不起作用。没有充分的理由。jQuery通过将废话隐藏在普通函数后面来实现正确的处理$
,因此您不必关心对象的实现方式。
为了使您可以方便地使用指定的原型创建对象,ECMAScript 5包含一个标准函数Object.create
。它的简化版本如下所示:
Object.create = function(prototype) {
var Type = function () {};
Type.prototype = prototype;
return new Type();
};
它只需要编写一个构造函数,然后使用进行调用即可new
。
什么时候可以避免使用原型?
与流行的OO语言(例如Java和C#)进行有用的比较。这些支持两种继承:
implement
一个interface
这样的类提供了自己独特的实施接口的每一个成员。extend
在class
其中提供某些方法的默认实现。在JavaScript中,原型继承是一种实现继承。因此,在某些情况下(在C#或Java中)您将从基类派生以获得默认行为,然后对这些行为进行一些小的修改以通过重写进行覆盖,然后在JavaScript中,原型继承才有意义。
但是,如果您处在使用C#或Java接口的情况下,则JavaScript不需要任何特定的语言功能。无需显式声明表示接口的内容,也无需将对象标记为“实现”该接口:
var duck = {
quack: function() { ... }
};
duck.quack(); // we're satisfied it's a duck!
换句话说,如果对象的每个“类型”都有自己的“方法”定义,则从原型继承没有任何价值。之后,这取决于您为每种类型分配多少个实例。但是在许多模块化设计中,只有一个给定类型的实例。
实际上,许多人已经暗示实现继承是邪恶的。就是说,如果某个类型有一些通用的操作,那么也许不把它们放到基类/超级类中,而是将它们作为普通的函数公开在某个模块中,然后再将对象传递给它们就可以了。您希望他们继续操作。
quack
函数处于原型中是很有意义的,许多鸭子实例都链接到该原型。2.对象文字语法{ ... }
创建一个实例(无需new
与之一起使用)。3.调用任何函数JS会导致在内存中创建至少一个对象-这就是所谓的arguments
对象并将其存储在调用中传递的参数:developer.mozilla.org/en/JavaScript/Reference/...
如果要声明对象的“非静态”方法,则应使用原型。
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.
this
示例this.getA = function(){alert("A")}
对吗?只需在构造函数内部定义方法,即可为对象创建一个非静态方法?
使用内置prototype
对象的一个原因是,如果您将多次复制一个对象,这些对象将共享共同的功能。通过将方法附加到原型,您可以节省每个方法创建的重复方法new
实例。但是,当您将方法附加到时prototype
,所有实例都可以访问这些方法。
假设您有一个基Car()
类/对象。
function Car() {
// do some car stuff
}
然后创建多个Car()
实例。
var volvo = new Car(),
saab = new Car();
现在,您知道每辆汽车都需要驾驶,打开等。不必将方法直接附加到Car()
类(每个创建的实例占用内存),您可以将方法附加到原型(仅创建方法)。一次),因此可以同时访问new volvo
和的那些方法saab
。
// 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'
Car.prototype = { ... }
必须在调用new Car()
jsfiddle中所示的jsfiddle 之前来:jsfiddle.net/mxacA。至于您的论点,这将是正确的方法:jsfiddle.net/Embnp。有趣的是,我不记得回答这个问题=)
当您要创建大量特定类型对象的副本时,请将函数放在原型对象上,并且它们都需要共享共同的行为。这样,每个功能只有一个副本即可节省一些内存,但这只是最简单的好处。
更改原型对象上的方法或添加方法会立即更改相应类型的所有实例的性质。
现在,为什么要执行所有这些操作主要取决于您自己的应用程序设计,以及您需要在客户端代码中执行的各种操作。(一个完全不同的故事是服务器中的代码;更容易想象在其中执行更多大规模的“ OO”代码。)
如果我用基于类的术语解释,那么Person是类,walk()是原型方法。因此,仅在您用此实例化新对象之后,walk()才会存在。
因此,如果您要像Person这样创建对象的副本,则可以创建许多用户。Prototype是一个很好的解决方案,因为它可以通过为内存中的每个对象共享/继承相同的函数副本来节省内存。
在这种情况下,static并不是很大的帮助。
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