什么是原型
js中的原型指的是一個(gè)對象可以從另一個(gè)對象繼承特性。每個(gè)對象都有一個(gè)原型對象,對象以其原型對象為模板,繼承其屬性,方法。原型對象也有自己的原型對象,這樣一層一層,通常稱為原型鏈。
準(zhǔn)確來說,這些屬性和方法,定義在對象的構(gòu)造函數(shù)(constructor functions)之上的prototype屬性上面,而不是對象實(shí)例本身。
js中鏈接對象實(shí)例和原型的是_proto_,它是從構(gòu)造函數(shù)的prototype派生的,之后上溯到原型鏈,在構(gòu)造器中找到這些屬性和方法。
js中不是所有的對象都可以作為原型對象,每個(gè)對象都是繼承自O(shè)bject,但是我們主動(dòng)設(shè)置一個(gè)對象的原型為另一個(gè)對象。
prototype屬性
繼承的屬性和方法被定義在prototype屬性上,prototype屬性的值是一個(gè)對象。
constructor屬性
每個(gè)實(shí)例對象都從原型中繼承了一個(gè)constructor屬性,該屬性指向了用于構(gòu)造此實(shí)例對象的構(gòu)造函數(shù)。
構(gòu)造函數(shù),原型,實(shí)例之間的關(guān)系

下面我們將通過一些例子來看一下
//構(gòu)造函數(shù)1
function Person( name,age ){
this.name = name;
this.age = age;
};
//構(gòu)造函數(shù)2
function Test (){
}
//實(shí)例1
var person1 = new Person("小明", 21);
//原型鏈為: person1 ====> Person ====> Object ====> null
console.log(person1.constructor);
/*output:
person1.constructor指向構(gòu)造函數(shù)Person
? Person(name, age) {
this.name = name;
this.age = age;
}
*/
console.log(person1.__proto__);
console.log(Person.prototype);
/*output:
{
constructor: ? Person(name, age)
__proto__: Object
}
*/
console.log(person1.__proto__ === Person.prototype); //true
//實(shí)例2;
var person2 = new Test();
//把實(shí)例person1作為person2的原型
person2.__proto__ = person1;
//原型鏈為: person2 ====> person1 ===> Person ===> Object ====>null
console.log(person2.name) //小明,繼承自person1
console.log(person2.constructor);
/*output:
? Person(name, age) {
this.name = name;
this.age = age;
}
*/
console.log(person2.__proto__);
/*output:
{
Person
age: 21
name: "小明"
__proto__:
{
constructor: ? Person(name, age)
__proto__: Object
}
}
*/
console.log(person2.__proto__.__proto__ === Person.prototype); //true
//實(shí)例3
//create() 實(shí)際做的是從指定原型對象創(chuàng)建一個(gè)新的對象。這里以 person1 為原型對象創(chuàng)建了 person3 對象。
var person3 = Object.create(person1);
//原型鏈為: person3 ====> person1 ===> Person ===> Object ====>null
console.log(person3.__proto__);
/*output:
{
Person
age: 21
name: "小明"
__proto__:
{
constructor: ? Person(name, age)
__proto__: Object
}
}
*/
不改變對象的原型鏈繼承另一個(gè)對象的方法
//構(gòu)造函數(shù)1
function Person( name,age ){
this.name = name;
this.age = age;
};
//構(gòu)造函數(shù)2
function Test (){
}
//方法一:
var person4 = new Test();
//用call或者apply來改變this,在person4的作用域里面去執(zhí)行Person
//Person.call(person4);
Person.apply(person4);
console.log(person4.__proto__);
/*
constructor: ? Test()
__proto__: Object
*/
//方法二: 可以直接在構(gòu)造函數(shù)里面使用apply或者call
//比如:
function Test (){
Person.call(this);
}
四個(gè)拓展原型鏈的方法
new操作符做了什么事情
//new 的過程
var obj = new Object(); //創(chuàng)建一個(gè)新對象
obj.__proto__ = A.prototype; //讓obj的__proto__指向A.prototype
A.call(obj) //在obj的作用環(huán)境執(zhí)行構(gòu)造函數(shù)的代碼,使this指向obj
return obj //返回實(shí)例對象