1.構(gòu)造函數(shù)
任何一個(gè)函數(shù)只要被new使用了,就是構(gòu)造函數(shù)。
構(gòu)造函數(shù)用來存放每一個(gè)實(shí)例自己具有的屬性和方法。
<script>
function Person(name,age){
//每一個(gè)實(shí)例有自己的名字和年齡,而不是所有的實(shí)例共享同一個(gè)名字和年齡
this.name=name;
this.age=age;
}
let p=new Person('abc',20);
console.log(p);
</script>

可以看到上面創(chuàng)建的P實(shí)例對象,具有__proto__屬性,指向的對象就是原型對象。同時(shí)構(gòu)造函數(shù)Person中prototype屬性指向的也是該原型對象,完全全等。
2.原型對象原型鏈

- 任何一個(gè)構(gòu)造函數(shù)在創(chuàng)建的時(shí)候,都有一個(gè)prototype屬性,該屬性指向原型對象。
- 任何一個(gè)引用對象(數(shù)組、對象、函數(shù)),都有一個(gè)__proto__屬性,該屬性也指向原型對象。
- 原型對象中有constructor屬性,指向構(gòu)造函數(shù);有__proto__屬性指向父類的原型對象。

原型對象中有一個(gè)constructor屬性,指向構(gòu)造函數(shù)Person(name,age)。
原型對象也有__proto__,指向其父類的原型對象,這里是指向Object的原型對象。
原型對象用來存放所有實(shí)例共享的屬性和方法。
<script>
function Person(name,age){
//每一個(gè)實(shí)例有自己的名字和年齡,而不是所有的實(shí)例共享同一個(gè)名字和年齡
this.name=name;
this.age=age;
}
//在原型對象中創(chuàng)建共享的方法
Person.prototype.getName=function(){
return this.name;
};
let p=new Person('abc',20);
//當(dāng)在實(shí)例中找不到調(diào)用的屬性或方法時(shí),就會沿著__proto__屬性指向的原型對象一層層的向上查找。(原型鏈)
//這里調(diào)用的是原型對象中的方法
console.log('name:'+p.getName());
console.log(p);
//在p實(shí)例對象的__proto__的__proto__中查找,
//也就是Object構(gòu)造函數(shù)的prototype指向的原型對象,
//這個(gè)Object.prototype.__proto__===null。避免死循環(huán)
p.toString();
</script>

3.instanceof
用于判斷引用類型的實(shí)例是屬于哪個(gè)構(gòu)造函數(shù)的方法。

原理:
-
判斷實(shí)例的__proto__指向的原型對象(隱試原型)與構(gòu)造函數(shù)的prototype屬性所指向的原型對象(顯式原型)是否是同一個(gè)。
-
子類型的實(shí)例instanceof父類型的構(gòu)造函數(shù),也會返回true
- 要更加詳細(xì)的識別是子類型的實(shí)例
實(shí)例對象.__proto__.constructor===構(gòu)造函數(shù)
4.繼承的實(shí)現(xiàn)方式
1.使用構(gòu)造函數(shù)實(shí)現(xiàn)繼承
<script>
/*1.使用構(gòu)造函數(shù)實(shí)現(xiàn)繼承*/
function Father(name,age){
this.name=name;
this.age=age;
}
//父類原型對象中的方法
Father.prototype.getName=function(){
console.log(this.name);
};
//父類原型對象中的方法
Father.prototype.getAge=function(){
console.log(this.age);
};
function Son(name,age){
Father.call(this,name,age);
}
let son =new Son('abc',13);
console.log(son);
</script>

缺點(diǎn):
只能繼承父類實(shí)例的屬性和方法,不能繼承父類原型對象中的屬性和方法。
2.使用原型鏈繼承
<script>
/*1.使用構(gòu)造函數(shù)實(shí)現(xiàn)繼承*/
function Father(name,age){
this.name=name;
this.age=age;
}
//父類原型對象中的方法
Father.prototype.getName=function(){
console.log(this.name);
};
//父類原型對象中的方法
Father.prototype.getAge=function(){
console.log(this.age);
};
function Son(name,age){
//Father.call(this,name,age);
}
//使用原型鏈實(shí)現(xiàn)繼承,將子類構(gòu)造函數(shù)的prototype指向的原型對象賦值
//為父類的一個(gè)實(shí)例。
Son.prototype=new Father();
</script>

缺點(diǎn):父類所有的屬性和方法,在子類中都成了原型對象中的屬性和方法。
3.組合式繼承
使用call方法來繼承構(gòu)造函數(shù)中的屬性和方法,
使用原型鏈來繼承原型對象的屬性和方法。
<script>
/*1.使用構(gòu)造函數(shù)實(shí)現(xiàn)繼承*/
function Father(name,age){
this.name=name;
this.age=age;
}
//父類原型對象中的方法
Father.prototype.getName=function(){
console.log(this.name);
};
//父類原型對象中的方法
Father.prototype.getAge=function(){
console.log(this.age);
};
function Son(name,age){
Father.call(this,name,age);
}
//使用原型鏈實(shí)現(xiàn)繼承,將子類構(gòu)造函數(shù)的prototype指向的原型對象賦值
//為父類的一個(gè)實(shí)例。
Son.prototype=new Father();
</script>

缺點(diǎn):子類的原型對象中有父類構(gòu)造函數(shù)中的屬性和方法,同時(shí)子類的實(shí)例中也有父類構(gòu)造函數(shù)中的屬性和方法,繼承了兩次。
4.改進(jìn)的組合繼承1
<script>
/*1.使用構(gòu)造函數(shù)實(shí)現(xiàn)繼承*/
function Father(name,age){
this.name=name;
this.age=age;
}
//父類原型對象中的方法
Father.prototype.getName=function(){
console.log(this.name);
};
//父類原型對象中的方法
Father.prototype.getAge=function(){
console.log(this.age);
};
function Son(name,age){
Father.call(this,name,age);
}
//使用原型鏈實(shí)現(xiàn)繼承,將子類構(gòu)造函數(shù)的prototype指向的原型對象賦值
//為父類構(gòu)造函數(shù)的原型對象。
Son.prototype=Father.prototype;
</script>

缺點(diǎn):用了父類的原型對象,父類原型對象中的constructor指向父類的構(gòu)造函數(shù)。
5.改進(jìn)的組合繼承2
<script>
/*1.使用構(gòu)造函數(shù)實(shí)現(xiàn)繼承*/
function Father(name,age){
this.name=name;
this.age=age;
}
//父類原型對象中的方法
Father.prototype.getName=function(){
console.log(this.name);
};
//父類原型對象中的方法
Father.prototype.getAge=function(){
console.log(this.age);
};
function Son(name,age){
Father.call(this,name,age);
}
//使用原型鏈實(shí)現(xiàn)繼承,將子類構(gòu)造函數(shù)的prototype指向的原型對象賦值
//為父類構(gòu)造函數(shù)的原型對象的副本。
Son.prototype=Object.create(Father.prototype);
//設(shè)置constructor為父類的構(gòu)造函數(shù)
Son.prototype.constructor=Son;
</script>

5.new關(guān)鍵字的執(zhí)行過程
<script>
function Person(name,age) {
this.name=name;
this.age=age;
}
function mynew(fn,name,age){
//1.創(chuàng)建一個(gè)繼承自構(gòu)造函數(shù)原型對象的空對象
let o=Object.create(fn.prototype);
//2.調(diào)用構(gòu)造函數(shù)為該對象賦值
let k=fn.call(o,name,age);
//3.如果構(gòu)造函數(shù)中返回的k是對象,則返回k
if(typeof k==='object')
return k;
//4.如果不是返回o
else
return o;
}
let person=mynew(Person,'abc',13);
console.log(person);
</script>


