转帖: http://www.alloyteam.com/2015/10/prototype/?hmsr=toutiao.io&bsh_bid=928776428
最近恰好有人问起关于 javascript 中的 prototype 相关的问题。特此简单地整理了一下,比较基础,希望能让有类型问题的同学,可以用这篇文章提供参考。
prototype 是通过调用构造函数而创建的对象实例的原型对象。
- 每一个新的函数,都会拥有一个 prototype 属性,这个属性指向函数的原型对象。
- 所有原型对象都有一个 constructor 属性,指向了 prototype 属性所在函数的指针,即 Cat.prototype.constructor == Cat
- prototype 对象是通过构造函数所产生的实例对象的原型对象,Cat.prototype.loveThing 为 prototype 添加属性,组成了这个prototype 对象。
- 实例对象拥有一个指针 [[prototype]] 指向了它的原型对象 prototype。
function Cat(name){ this.name = name; } Cat.prototype.loveThing = [‘apple‘]; Cat.prototype.sayHi = function(){ alert(this.name); } var tomcat = new Cat(‘TOM‘); tomcat.sayHi(); // TOM tomcat.loveThing.push(‘orange‘); alert(tomcat.loveThing); // apple,orange var redcat = new Cat(‘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 相同的结果。
重写原型对象切断现有原型与任何之前已经存在的对象实例直接的联系,他们的引用仍然是最初的原型。
function Person(){}; var xiaoming = new Person(); Person.prototype = { constructor: Person, sayHi: function(){ console.log(‘hi‘) } } xiaoming.sayHi(); // err
常用原型语法
function Cat(name){ this.name = name; } Cat.prototype = { constructor: Cat, //重新指向Cat sayHi: function(){ console.log(this.name); } } var tomCat = new Cat(); console.log(tomCat instanceof Cat); // true console.log(tomCat instanceof Object); //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() 这个方法来过滤出来自实例的属性
var obj = {name: 123} for(var key in obj){ if(Object.hasOwnProperty(key)){ // ... 这些key来自实例,非来自原型。 } } // 另: es5 中的 object.keys() 方法能够返回所有可枚举属性的字符串数组