1.什么是原型链?
无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype
属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor
(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。
以下面这个空函数fun
为例,当我们在程序中写了这样一个函数,js引擎实际上做了这么几件事:
- 为函数fun创建了一个
prototype
属性,可以把这个属性理解为一个对象(也就是原型对象)。 - 为
prototype
属性(原型对象)赋一个constructor
属性。 - 让
constructor
的值为指向fun函数
的指针。
function fun() {}
console.log(fun.prototype.constructor);//
2. 利用原型链的方式创建一个Person对象
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.sayName();//"Nicholas"
各个对象之间的关系如下图:
2.1 实例可以拥有自己的属性
var person1 = new Person();
var person2 = new Person();
person1.name = "Greg";
alert(person1.name);//"Greg"——来自实例
alert(person2.name);//"Nicholas"——来自原型
2.2 delete只能删除实例的属性,不能删除原型的属性
var person1 = new Person();
person1.name = "Greg";
alert(person1.name);//"Greg"——来自实例
delete person1.name;
alert(person1.name); //"Nicholas"——来自原型
2.3 判断实例中是否包含某个属性hasOwnProperty()
var person1 = new Person();
var person2 = new Person();
alert(person1.hasOwnProperty("name"));//false
person1.name = "Greg";
alert(person1.hasOwnProperty("name")); //true
alert(person2.name);//"Nicholas"——来自原型
alert(person2.hasOwnProperty("name")); //false
delete person1.name;
alert(person1.name);//"Nicholas"——来自原型
alert(person1.hasOwnProperty("name")); //false
上面例子执行过程中原型链的变化如下:
2.4 重写整个原型对象
虽然可以利用prototype
重写原型对象的属性和方法,但是如果重写整个原型对象,就会出现出现不一样的情况。因为原型修改为另外一个对象就等于切断了构造函数与最初原型之间的联系。实例中的指针仅指向原型,而不指向构造函数。
看下面这个例子:
function Person(){
}
var friend = new Person();
Person.prototype = {
constructor: Person,
name : "Nicholas",
age : 29,
job : "Software Engineer",
sayName : function () {
alert(this.name);
}
};
friend.sayName();//浏览器报错
代码执行过程中原型链的变化: