最近恰好有人问起关于 javascript 中的 prototype 相关的问题。特此简单地整理了一下,比较基础,希望能让有类型问题的同学,可以用这篇文章提供参考。
prototype 是通过调用构造函数而创建的对象实例的原型对象。
functionCat(name){ this.name=name; } Cat.prototype.loveThing=['apple']; Cat.prototype.sayHi=function(){ alert(this.name); } vartomcat=newCat('TOM'); tomcat.sayHi();// TOM tomcat.loveThing.push('orange'); alert(tomcat.loveThing);// apple,orange varredcat=newCat('RED'); tomcat.sayHi();// RED alert(redcat.loveThing);// apple,orange
可以看到,上面 tomcat 还有 redcat 作为 Cat 的实例,都 sayHi 出各自构造函数传入的 name。这并不奇怪。而 retcat 的loveThing 和 tomcat 一样,都是 apple,orange ?
当实例 tomcat 调用 tomcat.loveThing 的时候,由于实例中没有 loveThing 这个属性(与其原型对象相同),所以会继续向上搜索,读取到其原型对象的 loveThing 属性。此时执行的 tomcat.loveThing.push(‘orange’),相当于对原型对象进行操作,类似 Cat.prototype.loveThing.push(‘orange’);由于原型对象为所有对象实例 共用 。所以,后来执行了 redcat.loveThing,相当于执行了 Cat.prototype.loveThing;从而得到与 tomcat 相同的结果。
重写原型对象切断现有原型与任何之前已经存在的对象实例直接的联系,他们的引用仍然是最初的原型。
functionPerson(){}; varxiaoming=newPerson(); Person.prototype={ constructor:Person, sayHi:function(){ console.log('hi') } } xiaoming.sayHi();// err
常用原型语法
functionCat(name){ this.name=name; } Cat.prototype={ constructor:Cat, //重新指向Cat sayHi:function(){ console.log(this.name); } } vartomCat=newCat(); console.log(tomCatinstanceofCat);// true console.log(tomCatinstanceofObject);//true
上面代码重写了 Cat 的 prototype 属性,由于每一个 prototype 一个对应的 constructor 属性,所以此时 constructor 指向了 Object
console.log(tomCat.constructor==Cat);//true
当没有对 constructor 重新指向时,会出现下面的情况。
console.log(tomCat.constructor==Object);//true console.log(tomCat.constructor==Cat);//false
for-in 与 hasOwnProperty()
由于 for-in 方法会将其实例还有原型的属性都输出,可以通过 hasOwnProperty() 这个方法来过滤出来自实例的属性
varobj={name:123} for(varkeyinobj){ if(Object.hasOwnProperty(key)){ // ... 这些key来自实例,非来自原型。 } } // 另: es5 中的 object.keys() 方法能够返回所有可枚举属性的字符串数组