prototype属性用于返回对象的类的原型。
拓展知识:
无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,该属性保存着函数的原型对象。prototype属性使我们有能力向原型对象添加属性和方法,并且这些属性和方法是这一类对象所共享的。另外所有函数的
默认原型都是Object的实例,因此所有的对象都具有Object的属性和方法,例如:toString()、valueOf()等。
通过prototype为function类添加的属性和方法只能在类型的实例上体现。
JavaScript内置对象的prototype属性是只读的,其本身就是一个对象,我们只能够对该对象的属性和方法进行操作,比如添加属性或方法、删除属性和方法,而不能使用另一个对象来替换该对象,哪怕是另外一个原型对象。(这里说的仅仅是JavaScript的内置对象,并不包括自定义的对象)。
所谓不能用另一个对象来替换该对象即是说用新对象(或原型对象)替换后,该对象原有的prototype对象属性将不存在了,这种做法从规范的角度不建议采用,下面举例说明这种情况:
var Person = function (){};
Person.prototype.ask = function (){
return "Person ask called"
}
var Programmer = function(){};
Programmer.prototype.writeName= function(){
return "Programmer writeName called"
}
Programmer.prototype = new Person();//更改Programmer的Prototype对象,不建议这种做法
var p = new Programmer();
p.writeName();//Error writeName未定义
p.ask();//Person ask called
prototype属性的设计来源
首先看一个具体的例子
function Person(){
this.say = function(name){
alert(name+" say hello");
};
}
var zhang = new Person();
zhang.say("zhang"); // zhang say hello
var li = new Person();
li.say("li"); // li say hello
// 为zhang 添加ask方法
zhang.ask = function(name){
alert(name+" ask");
};
// 调用zhang的ask方法
zhang.ask("zhang");// zhang ask
// 调用li的ask方法
li.ask("li"); //将会报错,因为li没有ask方法
如上面代码的最后一行报错,是由于在不引入prototype前,实例之间属性和方法都是独立存在,对一个对象的属性和方法进行添加/删除,并不会影响到另一个"同类"对象。这样的设计就造成了极大的资源浪费。至于属性,有些时候我们也是希望能够在两个对象内部共享一些属性的。于是JavaScript的设计者布兰登·艾奇(Brendan Eich)就想到在函数中添加一个prototype属性,这个属性用来保存一些供所有"同类"实例对象共享使用的属性和方法。
当我们访问一个实例对象的属性和方法时,JavaScript先查找对象本身是否存在这些属性或方法,如果有就直接返回;如果不具备,就查询创建该对象的类(即函数)的prototype属性中是否存在同名的属性或方法,如果有就返回。由于prototype属性本身就是一个对象(一般称之为原型对象),这看起来就有点像"继承":实例对象"继承"了prototype对象的属性和方法。
注:在实例上不能使用prototype,否则发生编译错误。
function Person(){
this.say = function(name){
alert(name+" say hello");
};
}
var zhang = new Person();
zhang.say("zhang"); // zhang say hello
var li = new Person();
li.say("li"); // li say hello
//为prototype添加ask方法
Person.prototype.ask= function(name){
alert(name+" ask");
};
// 调用zhang的ask方法
zhang.ask("zhang");// zhang ask
// 调用li的ask方法
li.ask("li");// li ask
拓展知识:
JS中的prototype和__proto__区别
prototype
是
函数的一个属性(每个函数都有一个prototype属性),这个属性是一个指针,指向一个对象。它是显示修改对象的原型的属性。
__proto__
是一个
对象拥有的内置属性(请注意:
prototype是函数的内置属性,__proto__是对象的内置属性),是JS内部使用寻找原型链的属性。
用chrome和FF都可以访问到对象的__proto__属性,IE不可以。
下面我们看下new 过程
var Person = function(){};
var p = new Person();
new的过程拆分成以下三步:
(1) var p={}; 也就是说,初始化一个对象p
(2) p.__proto__ = Person.prototype;
(3) Person.call(p); 也就是说构造p,也可以称之为初始化p
当调用p的内部方法(或属性)时
会先在this的内部查找(也就是构造函数内部),如果没有找到然后再沿着原型链向上追溯。
这里的向上追溯是怎么向上的呢?这里就要使用__proto__属性来链接到原型(也就是Person.prototype)进行查找。最终在原型上找到方法(或属性)。