Javascript中的prototype

  Javacript中的Prototype应该算是一个非常容易混淆的概念,就算是经验丰富的开发者也会对这个概念了解不足。我相信这些麻烦的根源来自于我们早期对prototype的使用,这些使用基本上就是new,constructor以及非常容易误解的那种隶属于某个方法的prototype属性。事实上,prototype是一个非常简单的概念。为了更好的理解它,我们需要忘记我们已经学过的在constructor时使用的prototype,从prototype的第一条原则开始。

什么是prototype?

Prototype就是一个特殊的对象,其他对象从它这边继承属性。

 

是不是任何对象都可以作为一个prototype?

是的

 

哪些对象拥有prototype?

Javascript默认任何对象都拥有一个prototype。由于prototype本身是一个对象,所以所有的prototype都拥有自己的prototype。(只有一个例外:在prototype链顶端的默认对象的prototype。后面会介绍prototype链)

 

什么是对象?

Javascript中的对象指的是任何没有排序的key-value键值对的集合。只要它不是一个javascript原语(undefined,null,boolean,number或者string),它就是一个对象。

 

你说所有的对象都有prototype,但是当我编写({}).prototype的时候,我获得的是undefined,你是不是疯了?

忘记你所学过的关于prototype属性的所有东西,这些东西正是使你对prototype产生疑惑的源泉。一个对象的真正的prototype存放在对象内部的[[Prototype]]属性中。ECMA 5中介绍了一个标准的访问方法Object.getPrototypeOf(object)。目前为止,firefox,safari,chrome和IE9中都实现了这个方法。除此之外,除了IE以外的所有浏览器都支持非标准的访问方法__proto__。如果仍然不行,我们可以通过访问对象的constructor来获取对象的prototype属性。

 

1 var a = {};
2 //在Opera和 IE<=8时失败
3 Object.getPrototypeOf(a); // [object Object]
4 
5  //在IE中失败
6 a.__proto__; // [object Object]
7 
8 //所有浏览器
9 a.constructor.prototype; // [object Object]

 

false是一个原语,那为什么false.__proto__可以返回值?

当请求一个原语的prototype时,这个原语会被强制转换成对象。

1 False.__proto__ ===  Boolean(false).__proto__;//true

 

我想用prototype来实现继承,应该怎么做?

对一个实例设置prototype基本上是没有意义的,这样做的效率和在实例中直接添加属相基本一样。如果我们想要一个对象去共享一个已有对象的功能,我们可以这么做:

1  //在IE<=8时失败
2  var a = {};
3  a.__proto__ = Array.prototype;
4  a.length; //0

 

prototype真正强大的地方在于多个实例共享一个通用的prototype。Prototype的属性只需要定义一次就可以被所有的实例所继承。

 

这个时候是不是该介绍constructor的概念了?

是的。Constructor提供了一种在实例创建的时候设置通用prototype的方便的跨浏览器机制。

首先,在javascript中不区分constructor和其他的function,所以每一个function都拥有一个prototype属性。反过来说,任何不是function的东西都没有这样一个属性。

 1 //永远不会成为constructor的function,拥有prototype属性
 2 Math.max.prototype; //[object Object]
 3 
 4 //可以成为constructor的function,也拥有prototype属性
 5 var A = function(name){
 6     This.name = name;
 7 };
 8 A.    prototype;//[object Object]
 9 
10 //Math不是function,所以没有prototype属性
11 Math.prototype; //null

现在prototype的定义就变成了:一个function的prototype属性,是在所有以这个function为constructor而创建出来的实例所共享的prototype对象。

 

比较重要的一点就是,function的prototype属性和它本身的prototype是没有关系的,比如下面的例子。

1 //(例子在IE中无法运行)
2 var A = function(name){
3     This.name = name;
4 };
5 A.prototype ==A.__proto__; //false
6 A.__proto__ == Function.prototype;

prototype使用的常见例子


常规prototype使用,添加方法:

 1  var circle = function(radius){
 2       This.radius = radius;
 3   }
 4  
 5   Circle.prototype.area = function(){
 6       Return Math.PI*this.radius*this.radius;
 7  }
 8  
 9 var a = new Circle(3), b = new Circle(4);
10 a.area().toFixed(2); //28.27
11 b.area().toFixed(2); //50.27

 

实例共享prototype的属性:

var A = function(name) {
    this.name = name;
}
var a = new A('alpha');
a.name; //'alpha'
A.prototype.x = 23;
a.x; //23

 

如果将A的prototype属性设置为一个新的对象,a.__prototype__仍然引用原来的对象:

1 var A = function(name) {
2     this.name = name;
3 }
4 var a = new A('alpha');
5 a.name; //'alpha'
6 A.prototype = {x:23};
7 a.x; //null

 

默认的prototype只有一个constructor属性:

1 var A = function() {};
2 A.prototype.constructor == A; //true
3 var a = new A();
4 a.constructor == A; //true (a的constructor属性继承于它的prototype)

 

prototype链(链顶的对象没有prototype)

1 a.__proto__ = b;
2 b.__proto__ = c;
3 c.__proto__ = {}; //默认的 object
4 {}.__proto__.__proto__; //null

 

 

posted @ 2012-07-11 13:27  chainsaw  阅读(215)  评论(0编辑  收藏  举报