面向?qū)ο?/strong>
1、類與實例
1.1.類的聲明
eg:
1. function Animal(){
this.name = "name";
}
2.ES6中類(class)的聲明
class Animal2{
constructor(){
this.name = name;
}
}
1.2.(如何通過類實例化生成對象)生成實例
eg:
//如果構(gòu)造函數(shù)后面沒有參數(shù)诊县,new后面這個()是可以不要的;
1.console.log(new Animal(),new Animal2());
2媚污、類與繼承
2.1.如何實現(xiàn)繼承富纸?
2.2.繼承的幾種方式园担、各個形式都有什么優(yōu)點和缺點?
繼承的本質(zhì)(原理)就是原型鏈缅糟。
1.借助構(gòu)造函數(shù)實現(xiàn)繼承
(只實現(xiàn)了部分繼承挺智,如果父類的屬性都在構(gòu)造函數(shù)上,那沒有問題窗宦;
如果父類的原型對象上還有方法赦颇,子類是拿不到這些方法的)
function Parent1(){
this.name = "parent1";
}
function Child(){
//call和apply改變的是函數(shù)運行上下文,把父級(Parent1這個構(gòu)造函數(shù))在子函數(shù)里執(zhí)行的話赴涵,
同時修改了父級構(gòu)造函數(shù)this的指向媒怯,從而導致了父類執(zhí)行的時候?qū)傩远紩煸贑hild類實例上去。
//將父級的構(gòu)造函數(shù)的this指向一個子構(gòu)造函數(shù)的實例上去髓窜,父級構(gòu)造函數(shù)所有的屬性在子類中也有
Parent1.call(this);
this.type="child1";
}
console.log(new Child());
缺點:Parent1原型鏈上的東西并沒有被Child所繼承扇苞;
沒有繼承父類原型對象上的方法,導致的并沒有真正的實現(xiàn)繼承寄纵;
function Parent1(){
this.name ="Parent1";
}
Perent1.prototype.say=function(){};
function Child1(){
Parent1.call(this);
this.type="child1";
}
console.log(new Child1(),new Child1().say());//say()不是一個function
2.借助原型鏈實現(xiàn)繼承(彌補構(gòu)造函數(shù)實現(xiàn)繼承不足)
function Parent2(){
this.name ="parent2";
}
function Child2(){
this.type="child2";
}
//prototype作用為了讓這個構(gòu)造函數(shù)(Child2)的實例能訪問到原型對象上
Child2.prototype = new Parent2();
console.log(new Child2()); //Child2{type:"child2",__proto__:Parent2}
console.log(new Child2().__proto__);//.__proto__===Child2.prototype
new Child2.__proto__.name;--->"Parent2"
缺點:
function Parent2(){
this.name ="parent2";
this.play=[1,2,3];
}
function Child2(){
this.type="child2";
}
Child2.prototype = new Parent2();
console.log(new Child2());
var s1= new Child2();
var s2= new Child2();
console.log(s1.play,s2.play);//[1,2,3];[1,2,3]
s1.play.push(4);
console.log(s1.play,s2.play);//[1,2,3,4];[1,2,3,4]
在一個類上實例了兩個對象鳖敷,改第一個對象的屬性,第二個對象也跟著改變擂啥;
引起這個問題的原因:原型鏈上的原型對象是共用的哄陶;
s1.__proto__===s2.__proto__;//true
3.組合方式(實現(xiàn)繼承的通用方式)
function Parent3(){
this.name ="Parent3";
}
function Child3(){
Parent3.call(this);//原型鏈上執(zhí)行了1次
this.type="child3";
}
//父類的構(gòu)造函數(shù)執(zhí)行了2次
Child3.prototype = new Parent3(); //new的時候執(zhí)行了一次
var s3 = new Child3();
var s4 = new Child3();
s3.play.push(4);
console.log(s3.play,s4.play);
console.log(s3.constructor);//Parent3
----因為prototype直接拿的父類的實例,它沒有自己的constructor哺壶,它的constructor是從這個
實例中繼承的屋吨,也就是原型鏈上一級拿過來的,它拿過來的肯定是Parent3的constructor山宾;
缺點:父類的構(gòu)造函數(shù)執(zhí)行了2次
4.(組合繼承的優(yōu)化)
//構(gòu)造函數(shù)體內(nèi)通過兩個構(gòu)造函數(shù)的組合能拿到所有構(gòu)造函數(shù)體內(nèi)的屬性和方法
function Parent4(){
this.name ="Parent4";
}
function Child4(){
Parent4.call(this);//父類只執(zhí)行了一次
this.type="child4";
}
//對象引用類型(優(yōu)點:原型對象是只是一個簡單的引用至扰,不會執(zhí)行父級的構(gòu)造函數(shù))
Child4.prototype = Parent4.prototype;
var s5 = new Child4();
var s6 = new Child4();
s5.play.push(4);
console.log(s5.play,s6.play);
//判斷這個對象是不是這個類的實例
console.log(s5 instanceof Child4,s5 instanceof Parent4);//true,true
問題:怎么區(qū)分一個對象是直接由它的子類實例化的,還是它的父類實例化的资锰?
(怎么區(qū)分s5是是Child4的實例還是Parent4直接實例化的敢课?)
//指向了父類Parent4{this.name="parent4";this.play=[1,2,3]}
console.log(s5.constructor);
---prototype里面有一個屬性constructor,而我們的子類原型對象和父類的原型對象是一個對象绷杜,這個對象的constructor
就是父類里的constructor直秆,這個父類的constructor指的是Parent4自己;
----因為prototype直接拿的父類的實例,它沒有自己的constructor鞭盟,它的constructor是從這個
實例中繼承的圾结,也就是原型鏈上一級拿過來的,它拿過來的肯定是Parent4的constructor齿诉;
5.組合繼承優(yōu)化2(完美版)
function Parent5(){
this.name ="name";
this.play=[1,2,3];
}
function Child5(){
Parent5.call(this);
this.type="Child5";
}
//Object.create創(chuàng)建對象的原理:
//--- Child4.prototype = Parent4.prototype;引用同一個對象筝野,說白是一個對象晌姚,缺點:它倆的構(gòu)造函數(shù)指向的是一個
(constructor是一個)無法區(qū)分實例是由父類創(chuàng)建的還是子類創(chuàng)建的;
//---Object.create(Parent5.prototype)歇竟;創(chuàng)建中間對象方法挥唠,就把兩個原型對象區(qū)分開,這個中間對象還具備一個特性就是它的原型
對象是父類的原型對象焕议,這樣在原型鏈上又開始連起來了宝磨。
--通過在給Child5原型對象上的constructor做修改,就能正常區(qū)分父類和子類的構(gòu)造函數(shù)了号坡。
Child5.prototype = Object.create(Parent5.prototype);
Child5.prototype.constructor = Child5;
var s7 = new Child5();
var s8 = new Child5();
s6.play.push(4);
console.log(s7 instanceof Child5,s7 instanceof Parent5);//true true
consoel.log(s7.constructor); //Child5
***為什么通過Object.create方法創(chuàng)建的這個對象就能作為它倆之間的橋梁呢懊烤?
Object.create創(chuàng)建的對象有什么特點?
--Object.create它創(chuàng)建的這個對象宽堆,原型對象就是參數(shù)腌紧;
原理:Child5實例的原型對象等于Child5.prototype,Child5.prototype又等于Object.create方法創(chuàng)建的對象,這個中間對象原型對象又是
(prototype)父類的原型對象畜隶,所以一級的上一級的上一級壁肋,通過這樣找實現(xiàn)了繼承;而且還達到了父類和子類原型對象的隔離籽慢;
對象通過.__proto__ (這個屬性往上找它的原型對象的)一級一級往上找浸遗;