my-blog
my-blog copied to clipboard
什么是原型链
当从一个对象那里调取属性或方法时,如果该对象自身不存在这样的属性或方法,就会去自己关联的prototype对象那里寻找,如果prototype没有,就会去prototype关联的前辈prototype那里寻找,如果再没有则继续查找Prototype.Prototype引用的对象,依次类推,直到Prototype.….Prototype为undefined(Object的Prototype就是undefined)从而形成了所谓的“原型链”。 其中foo是Function对象的实例。而Function的原型对象同时又是Object的实例。这样就构成了一条原型链。
instanceof 确定原型和实例之间的关系
用来判断某个构造函数的prototype属性是否存在另外一个要检测对象的原型链上
对象的__proto__指向自己构造函数的prototype。obj.proto.proto...的原型链由此产生,包括我们的操作符instanceof正是通过探测obj.proto.proto... === Constructor.prototype来验证obj是否是Constructor的实例。
function C(){}
var o = new C(){}
//true 因为Object.getPrototypeOf(o) === C.prototype
o instanceof C
instanceof只能用来判断对象和函数,不能用来判断字符串和数字
isPrototypeOf
用于测试一个对象是否存在于另一个对象的原型链上。 判断父级对象 可检查整个原型链
原型链
想要理解原型链,先要了解什么是原型
一、原型模式
我们创建的每个函数都有一个==prototype==(原型)属性,prototype属性指向原型对象。通过该函数创建的实例对象会共享原型对象上的所有属性和方法。
function Person(){
}
Person.prototype.name = 'test';
Person.prototype.age = 25;
Person.prototype.sayName = function(){
console.log(this.name);
}
const person1 = new Person();
person1.sayName(); //'test'
const person2 = new Person();
person2.sayName(); //'test'
console.log(person1.sayName === person2.sayName); //true
二、原型对象
- 理解原型对象
只要创建了一个函数,就会为该函数生成一个==prototype==属性(指向函数的原型对象)。默认情况下,原型对象会自动获得一个==constructor==属性(构造函数属性),这个属性包含一个指向prototype属性所在函数的指针。当调用该函数创建一个实例后,该实例内部将包含一个指针[[Prototype]](内部属性),指向构造函数的原型对象。虽然在脚本中没有标准的方式访问[[Prototype]],但Firefox、Safari和Chrome在每个对象上都支持一个属性__proto__。而在其他实现中,这个属性对脚本则是完全不可见的。

虽然在所有实现中都无法访问到[[Prototype]],但可以通过==isPrototypeOf==方法来确定对象之间是否存在这种关系。如果[[Prototype]]指向调用isPrototypeOf()方法的对象(Person.prototype),那么这个方法就返回true。
Person.prototype.isPrototypeOf(person1); //true
Person.prototype.isPrototypeOf(person2); //true
==Object.getPrototypeOf==方法可以返回[[Prototype]]的值。例如:
Object.getPrototypeOf(person1) === Person.prototype // true
Object.getPrototypeOf(person1).name // "test"
每当读取对象的某个属性时,都会首先从对象实例本身开始搜索,如果没有则继续搜索原型对象中的属性。虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。
person1.name = "Greg";
console.log(person1.name); // "Greg" 来自实例本身
console.log(person2.name); // "test" 来自原型对象
==hasOwnProperty==方法可以检测一个属性是存在于实例中,还是存在于原型中(从Object继承来的),只在给定属性存在于对象实例中时,才会返回true。
person1.hasOwnProperty("name"); //true
person2.hasOwnProperty("name"); //false
delete person1.name;
person1.hasOwnProperty("name"); //false
- 原型与in操作符
单独使用in操作符时,无论属性存在于实例中还是原型中,只要能访问到给定属性都返回true。
person1.hasOwnProperty('name'); //false
'name' in person1; //true
person2.hasOwnProperty('name'); //false
'name' in person2; //true
person1.name = 'ohyes';
person1.name; // 'ohyes'
person1.hasOwnProperty('name'); //true
'name' in person1; //true
//通过使用hasOwnProperty方法和in操作符可以确定属性是存在于实例中还是原型中
function hasPrototypeProperty(obj,name){
return !obj.hasOwnProperty(name) && name in obj;
}
//属性存在于实例中,返回false;存在于原型中返回true
for - in循环,能够返回对象中所有可枚举的属性,无论存在于实例中还是原型中。屏蔽了原型中不可枚举属性的实例属性也可以在for-in循环中返回。但是在IE8以及更早版本有bug,即屏蔽不可枚举属性的实例属性不会出现在for-in 循环中。
要取得对象上所有可枚举的实例属性,可以使用Object.keys()方法。
Object.keys(Person.prototype); // ["name", "age", "sayName"]
Object.keys(person1); // ["name"]
如果想要得到所有的实例属性,无论是否可枚举,可以使用Object.getOwnPropertyNames()方法
Object.getOwnPropertyNames(Person.prototype); // ["constructor", "name", "age", "sayName"]
- 原型对象的问题
原型中所有属性是被很多实例共享的。对于包含引用类型值的属性的原型对象,会有特别的问题。
//在实例中修改了原型上的引用类型的属性,会在所有实例上反映出来
Person.prototype.friends = ['one', 'two'];
person1.friends.push('three');
person1.friends; // ["one", "two", "three"]
person2.friends; // ["one", "two", "three"]
person2.friends === person1.friends; // true
三、原型链
原型链是实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。每个构造函数都有一个prototype属性,指向原型对象。原型对象都包含一个指向构造函数的指针(constructor)。把构造函数的prototype属性修改成另一个构造函数的实例,此时原型对象就将包含指向另一个原型的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。这就是原型链的概念。
//修改构造函数的prototype属性指向另一个构造函数的实例,实现继承
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
}
function SubType(){
this.subproperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.subproperty;
}
let instance = new SubType();
console.log(instance.getSuperValue()); //true