ECMAScript有兩種開(kāi)發(fā)模式:1.函數(shù)式(過(guò)程化);2.面向?qū)ο?OOP);
一 創(chuàng)建對(duì)象
1.普通的創(chuàng)建對(duì)象
// 創(chuàng)建一個(gè)對(duì)象,然后給這個(gè)對(duì)象新的屬性和方法;
var box = new Object(); // 創(chuàng)建一個(gè)Object對(duì)象;
box.name = 'lee'; // 創(chuàng)建一個(gè)name屬性并賦值;
box.age = 100;
box.run = function(){ // 創(chuàng)建一個(gè)run()方法并返回值;
return this.name+this.age+'運(yùn)行中...';
}
console.log(box.run()); // 輸入屬性和方法的值;
// 缺點(diǎn):想創(chuàng)建類似的對(duì)象,就會(huì)產(chǎn)生大量的代碼;
2. 工廠模式創(chuàng)建對(duì)象
// 這種方法就是為了解決實(shí)例化對(duì)象產(chǎn)生大量代碼重復(fù)的問(wèn)題;
function createObject(name,age){ // 集中創(chuàng)建函數(shù)體;
var obj = new Object; // 函數(shù)體內(nèi)創(chuàng)建Object;
obj.name = name;
obj.age = age;
obj.run = function(){
return this.name+this.age+"運(yùn)行中...";
};
return obj;
}
var box1 = createObject("lee",100); // 實(shí)例化;調(diào)用函數(shù)并傳參;
var box2 = createObject("jack",200); // 實(shí)例二;
console.log(box1.run()+box2.run()); // 實(shí)例保持相對(duì)獨(dú)立;
// 缺點(diǎn):對(duì)象與實(shí)例的識(shí)別問(wèn)題;無(wú)法搞清楚它們到底是那個(gè)對(duì)象的實(shí)例;
console.log(typeof box1); // Object;
3.構(gòu)造函數(shù)創(chuàng)建對(duì)象
// ECMAScript采用構(gòu)造函數(shù)(構(gòu)造方法)可用來(lái)創(chuàng)建特定的對(duì)象;
function Box(name,age){ // 構(gòu)造函數(shù)模式;
this.name = name; // this代表對(duì)象Box;
this.age = age;
this.run = function(){
return this.name+this.age+"運(yùn)行中...";
};
}
var box1 = new Box("lee",100); // 要?jiǎng)?chuàng)建對(duì)象的實(shí)例必須用new操作符;
var box2 = new Box("jack",200); // box1和box2都是Box對(duì)象的實(shí)例;
console.log(box1 instanceof Box); // true;很清晰的識(shí)別box1從屬于Box;
// 使用構(gòu)造函數(shù),即解決了重復(fù)實(shí)例化的問(wèn)題,有解決了對(duì)象識(shí)別的問(wèn)題;
使用構(gòu)造函數(shù)與工廠模式不同之處:
(1).構(gòu)造函數(shù)方法沒(méi)有顯示的創(chuàng)建對(duì)象(new Object);
(2).直接將屬性和方法賦值給this對(duì)象;
(3).沒(méi)有return語(yǔ)句;1 // 構(gòu)造函數(shù)規(guī)范:
(1).函數(shù)名(function Box)和實(shí)例化構(gòu)造名(new Box)相同且大寫(xiě);
(2).通過(guò)構(gòu)造函數(shù)創(chuàng)建實(shí)例對(duì)象,必須使用new運(yùn)算符;
// 構(gòu)造函數(shù)和普通函數(shù)的區(qū)別:
var box = new Box('lee',100); // 構(gòu)造模式調(diào)用;
Box('lee',200); // 普通模式調(diào)用,無(wú)效;
var o = new Object();
Box.call(o,'jack',200); // 對(duì)象冒充調(diào)用;
// 將Box對(duì)象作用域擴(kuò)充到對(duì)象o;Box()方法的運(yùn)行環(huán)境已經(jīng)變成了對(duì)象o里;
構(gòu)造函數(shù)的問(wèn)題:
使用構(gòu)造函數(shù)創(chuàng)建每個(gè)實(shí)例的時(shí)候,構(gòu)造函數(shù)里的方法都要在每個(gè)實(shí)例上重新創(chuàng)建一遍;
因?yàn)镋CMAScript中的函數(shù)是對(duì)象,因此每定義一個(gè)函數(shù),也就是實(shí)例化了一個(gè)對(duì)象;
以這種方式創(chuàng)建函數(shù),會(huì)導(dǎo)致不同的作用域鏈和標(biāo)識(shí)符解析;
二 原型
// 我們創(chuàng)建的每個(gè)函數(shù)都有一個(gè)prototype(原型)屬性,這個(gè)屬性是一個(gè)對(duì)象;
// 用途:包含可以由特定類型的所有實(shí)例共享的屬性和方法;
// 理解:prototype是通過(guò)調(diào)用構(gòu)造函數(shù)創(chuàng)建的那個(gè)對(duì)象的原型對(duì)象;
// 使用原型的好處是可以讓所有對(duì)象實(shí)例共享它所包含的屬性和方法;
// 也就是說(shuō),不必在構(gòu)造函數(shù)中定義對(duì)象信息(屬性/方法),而是可以直接將這些信息添加到原型中;
1.原型模式(prototype添加屬性和方法)
1.原型模式
function Box(){} // 聲明構(gòu)造函數(shù);
Box.prototype.name = 'Lee'; // 在原型里添加屬性和方法;
Box.prototype.age = 100;
Box.prototype.run = function() {
return this.name+this.age+'運(yùn)行中...';
};
var box1 = new Box();
var box2 = new Box();
console.log(box1.run==box2.run); // =>true;方法引用的地址保持一致;
// 在原型中多了兩個(gè)屬性,這兩個(gè)原型屬性都是創(chuàng)建對(duì)象時(shí)自動(dòng)生成的;
// 1.__proto__:構(gòu)造函數(shù)指向原型對(duì)象的一個(gè)指針;它的作用:指向構(gòu)造函數(shù)的原型的屬性constructor;
14// IE瀏覽器在腳本訪問(wèn)__proto__會(huì)不能識(shí)別; 15
// 判斷一個(gè)實(shí)例對(duì)象是否指向了該構(gòu)造函數(shù)的原型對(duì)象,可以使用isPrototypeOf()方法來(lái)測(cè)試;
console.log(Box.prototype.isPrototypeOf(box)); // =>true; 只要實(shí)例化對(duì)象,即都會(huì)指向;
// 原型模式的執(zhí)行流程:
// 1.先查找構(gòu)造函數(shù)對(duì)象的實(shí)例里的屬性或方法,若有,立刻返回;
// 2.若構(gòu)造函數(shù)對(duì)象的實(shí)例里沒(méi)有,則去它的原型對(duì)象里找,若有,就返回;
// 雖然我們可以通過(guò)對(duì)象實(shí)例訪問(wèn)保存在原型中的值,但卻不能訪問(wèn)通過(guò)對(duì)象實(shí)例重寫(xiě)原型中的值;
var box1 = new Box();
console.log(box1.name); // Lee; 原型里的值;
bo1.name = 'jack';
console.log(box1.name); // Jack;實(shí)例自己賦的值;
var box2 = new Box();
console.log(box2.name); // Lee;原型里的值;沒(méi)有被box1修改;
// 如果想要box1繼續(xù)訪問(wèn)原型里的值,可以把構(gòu)造函數(shù)里的屬性刪除即可;
delete box1.name; // 刪除實(shí)例自己的屬性;
console.log(box1.name); // Lee; 原型里原來(lái)的值;
JavaScript 面向?qū)ο笈c原型 三聯(lián)
2.原型與in操作符
如何判斷屬性是在構(gòu)造函數(shù)的實(shí)例里,還是在原型里? 可以用hasOwnProperty()函數(shù)來(lái)驗(yàn)證;
console.log(box.hasOwnProperty('name')); // 實(shí)例里若有返回true,否則返回false;
in操作符會(huì)在通過(guò)對(duì)象能夠訪問(wèn)給定屬性時(shí)返回true,無(wú)論該屬性存在與實(shí)例中還是原型中;
console.log('name' in box); // =>true,存在實(shí)例中或原型中;3.更簡(jiǎn)單的原型語(yǔ)法(原型+字面量模式)
3.更簡(jiǎn)單的原型語(yǔ)法(原型+字面量模式)
function Box(){};
Box.prototype = { // 以字面量形式創(chuàng)建包含屬性和方法的新對(duì)象;
name:'Lee',
age:100,
run:function(){
return this.name+this.age+'運(yùn)行中...';
}
};
// 使用構(gòu)造函數(shù)創(chuàng)建原型對(duì)象和使用字面量創(chuàng)建原型對(duì)象在使用上基本相同;
// 但是,使用字面量創(chuàng)建的原型對(duì)象使用constructor屬性不會(huì)指向?qū)嵗?而是指向原型對(duì)象Object;構(gòu)造函數(shù)的方式則相反;
var box = new Box();
console.log(box instanceof Box);
console.log(box instanceof Object);
console.log(box.constructor == Box); // 字面量方式,返回false;
console.log(box.constructor == Object); // 字面量方式,返回true;
// 如果想讓字面量方式的constructor指向?qū)嵗龑?duì)象:
Box.prototype = {
constructor:Box, // 直接強(qiáng)制指向即可;
}
// PS:字面量方式為什么constructor會(huì)指向Object?
// 因?yàn)锽ox.prototype={}這種字面量寫(xiě)法就是創(chuàng)建一個(gè)新對(duì)象;
// 而每創(chuàng)建一個(gè)函數(shù),就會(huì)同時(shí)創(chuàng)建它的prototype,這個(gè)對(duì)象也會(huì)自動(dòng)獲取constructor屬性;
// 所以,新對(duì)象的constructor重寫(xiě)了Box原來(lái)的constructor,因此指向了新對(duì)象,
// 那個(gè)新對(duì)象沒(méi)有指定構(gòu)造函數(shù),那么就默認(rèn)為是Object;
4.原型的動(dòng)態(tài)性(重寫(xiě)會(huì)覆蓋之前的內(nèi)容)
// 原型的聲明是有先后順序的,所以,重寫(xiě)的原型會(huì)切斷之前的原型;
function Box(){};
Box.prototype = {
constructor:Box,
name:'Lee',
age:100,
run:function(){
return this.age+'運(yùn)行中...';
}
};
Box.prototype = { // 原型重寫(xiě)了,覆蓋了之前的原型;
age:200,
run:function(){
return this.age+'運(yùn)行中...';
}
}
var box = new Box();
console.log(box.run()); // =>200運(yùn)行中...;
// 重寫(xiě)原型對(duì)象切斷了現(xiàn)有原型與任何之前已經(jīng)存在的對(duì)象實(shí)例之間的聯(lián)系;對(duì)象實(shí)例引用的仍然是最初的原型;
5.原生對(duì)象的原型
// 原型對(duì)象不僅僅可以在自定義對(duì)象的情況下使用,而是ECMAScript內(nèi)置的引用類型都可以使用這種方式,
// 并且內(nèi)置的引用類型本身也是用了原型;
console.log(Array.prototype.sort); // =>function sort() { [native code] };
console.log(String.prototype.substring); // =>function substring() { [native code] };
6.原型對(duì)象的問(wèn)題
// 原型模式創(chuàng)建對(duì)象缺點(diǎn):省略了構(gòu)造函數(shù)傳參初始化這一過(guò)程,帶來(lái)的缺點(diǎn)就是初始化的值都是一致的;
// 而原型最大的有點(diǎn)就是共享,屬性共享;
// 但是,如果原型中的屬性包含引用類型(對(duì)象),共享就會(huì)存在一定問(wèn)題;
function Box(){};
Box.prototype = {
constructor:Box,
name:'Lee',
age:100,
family:['father','mother'],
run:function(){
return this.name+this.age+this.family;
}
};
var box1 = new Box();
box1.family.push('sister'); // 為box1的family屬性添加了sister;而這個(gè)屬性被共享到原型了;
console.log(box1.run()); // =>Lee100father,mother,sister;
var box2 = new Box();
console.log(box2.run()); // =>Lee100father,mother,sister;
// 數(shù)據(jù)共享導(dǎo)致實(shí)例化出的數(shù)據(jù)不能保存自己的特性;
7.組合使用構(gòu)造函數(shù)模式(對(duì)象不共享的數(shù)據(jù))和原型模式(對(duì)象共享的數(shù)據(jù))
// 為了解決構(gòu)造傳參和共享問(wèn)題,組合構(gòu)造函數(shù)+原型模式:
function Box(name,age){ // 不共享的使用構(gòu)造函數(shù);
this.name = name;
this.age = age;
this.family = ['father','moter'];
};
Box.prototype = { // 共享的使用原型模式;
constructor:Box,
run:function(){
return this.name+this.age+this.family;
}
};
// PS:這種混合模式很好的解決了傳參和引用共享的大難題;是創(chuàng)建對(duì)象比較好的方法;
8.動(dòng)態(tài)原型模式(將原型封裝到構(gòu)造函數(shù)里)
// 原型模式,不管是否調(diào)用了原型中的共享方法,它都會(huì)初始化原型中的方法;
// 并且在聲明一個(gè)對(duì)象時(shí),構(gòu)造函數(shù)+原型讓人感覺(jué)怪異;最好把構(gòu)造函數(shù)和原型封裝到一起;
function Box(name,age){ // 將所有信息封裝到構(gòu)造函數(shù)體內(nèi);
this.name = name;
this.age = age;
// 當(dāng)?shù)谝淮握{(diào)用構(gòu)造函數(shù)時(shí),run()方法不存在,然后執(zhí)行初始化原型;
// 當(dāng)?shù)诙握{(diào)用,就不會(huì)初始化,并且第二次創(chuàng)建新對(duì)象,原型也不會(huì)載初始化;
// 這樣既得到了封裝,又實(shí)現(xiàn)了原型方法共享,并且屬性都保持獨(dú)立;
if(typeof this.run != 'function'){ // 僅在第一次調(diào)用時(shí)初始化;
Box.prototype.run = function (){
return this.name+this.age+'運(yùn)行中...';
};
}
};
var box = new Box('lee',10);
console.log(box.run());
// PS:使用動(dòng)態(tài)原型模式,要注意一點(diǎn),不可以再使用字面量的方式重寫(xiě)原型,因?yàn)闀?huì)切斷實(shí)例和新原型之間的聯(lián)系;
9.寄生構(gòu)造函數(shù)
// 寄生構(gòu)造函數(shù),其實(shí)就是工廠模式+構(gòu)造模式;這種模式比較通用,但不能確定對(duì)象關(guān)系;
function Box(name,age){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function (){
return this.name+this.age+'運(yùn)行中...';
};
return obj;
}
三 繼承
1.原型鏈
// 繼承是面向?qū)ο笾幸粋€(gè)比較核心的概念;
// 其他正統(tǒng)面向?qū)ο笳Z(yǔ)言都會(huì)用兩種方式實(shí)現(xiàn)繼承:一個(gè)是接口實(shí)現(xiàn),一個(gè)是繼承;
// 而ECMAScript只支持繼承,不支持接口實(shí)現(xiàn),而實(shí)現(xiàn)繼承的方式依靠原型鏈完成;
// 實(shí)質(zhì):利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法;
// 原型繼承鏈:Box ==>> Desk ==>> Table;
function Box(){ // Box構(gòu)造;
this.name = 'Lee';
}
function Desk(){ // Desk構(gòu)造;
this.age = 100;
}
Desk.prototype = new Box(); // 通過(guò)創(chuàng)建Box實(shí)例,并賦值給Desk.prototype實(shí)現(xiàn)的;通過(guò)原型,形成鏈條;
// 實(shí)質(zhì)是:重寫(xiě)了Desk的原型對(duì)象,取而代之的是一個(gè)新類型Box的實(shí)例;
// 也就是說(shuō)原來(lái)存在于Box實(shí)例中的屬性和方法,現(xiàn)在也存在與Desk.prototype中了;
var desk = new Desk();
console.log(desk.age); // 100;
console.log(desk.name); // =>Lee;
function Table(){
this.level = 'AAA';
}
Table.prototype = new Desk(); // 繼續(xù)原型鏈繼承;Table繼承了Desk;
var table = new Table();
console.log(table.name); // Lee;
2.原型與實(shí)例的關(guān)系;
// PS:以上原型鏈繼承缺少一環(huán),那就是Object,所有的構(gòu)造函數(shù)都繼承自O(shè)bject;
// 而繼承Object是自動(dòng)完成的,并不需要手動(dòng)繼承;
console.log(table instanceof Object); // =>true;
console.log(desk instanceof Table); // =>false;Desk是Table的超類;
console.log(table instanceof Desk); // =>true;
console.log(table instanceof Box); // =>true;
// 在JS中,被繼承的函數(shù)稱為超類型(父類,基類);
// 繼承的函數(shù)稱為子類型(子類,派生類);
// 繼承問(wèn)題:
// 字面量重寫(xiě)原型會(huì)中斷關(guān)系;
// 子類型無(wú)法給超類型傳遞參數(shù);
3.借用構(gòu)造函數(shù)(對(duì)象冒充)
// 為了解決引用共享和給超類型無(wú)法傳參問(wèn)題;
// 在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù);
function Box(age){
this.name = ['Lee','Jack','Hello'];
this.age = age;
}
function Desk(age){
// 繼承了Box;同時(shí)還傳遞了參數(shù);
// 這樣一來(lái),就會(huì)在新Desk對(duì)象上執(zhí)行Box()函數(shù)中定義的所有對(duì)象初始化代碼;
Box.call(this,age); // 對(duì)象冒充,Desk繼承Box,并可以給超類型傳參;
// 為了確保Box構(gòu)造函數(shù)不會(huì)重寫(xiě)子類型的屬性,可以在超類型構(gòu)造函數(shù)后,再添加應(yīng)該在子類型中定義的屬性;
this.height = 175;
}
var desk = new Desk(200); // 向Desk()函數(shù)傳參,再通過(guò)函數(shù)冒用向Box()函數(shù)傳參;
console.log(desk.age); // =>200;
console.log(desk.name); // =>['Lee','Jack','Hello'];
desk.name.push('AAA'); // =>添加的新數(shù)據(jù),只添加給desk;
console.log(desk.name); // =>['Lee','Jack','Hello','AAA'];
4.組合繼承(原型鏈+借用構(gòu)造函數(shù))
// 借用構(gòu)造函數(shù)雖然解決了引用共享和給超類型無(wú)法傳參問(wèn)題,但是沒(méi)有使用原型,復(fù)用則無(wú)從談起;所以需要組合繼承模式;
// 使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承;
// 通過(guò)借用構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承;
// 這樣,既通過(guò)在原型上定義方法實(shí)現(xiàn)了函數(shù)復(fù)用,又能保證每個(gè)實(shí)例都有他自己的屬性;
function Box(age){ // 構(gòu)造函數(shù);
this.name = ['Lee','Jack','Hello'];
this.age = age;
}
Box.prototype.run = function(){ // 原型;
return this.name+this.age;
}
function Desk(age){
Box.call(this,age); // 繼承屬性; 對(duì)象冒充; 將Box對(duì)象的作用域擴(kuò)充到Desk中,Desk就會(huì)繼承Box里的屬性和方法;
}
Desk.prototype = new Box(); // 繼承方法; 原型鏈繼承;
var desk = new Desk(100);
console.log(desk.run()); // =>Lee,Jack,Hello100
// 最常用的繼承模式;
5.原型式繼承?
// 這種繼承借助原型并基于已有的對(duì)象創(chuàng)建對(duì)象,同時(shí)還不必因此創(chuàng)建自定義類型;
function obj(o){ // 傳遞一個(gè)字面量函數(shù);
function F(){}; // 創(chuàng)建一個(gè)構(gòu)造函數(shù);
F.prototype = o; // 把字面量函數(shù)賦值給構(gòu)造函數(shù)的原型;
return new F(); // 返回實(shí)例化的構(gòu)造函數(shù);
}
var box = { // 字面量對(duì)象;
name:'Lee',
arr:['brother','sisiter']
};
var box1 = obj(box);
console.log(box1.name); // =>Lee;
box1.name = 'Jack';
console.log(box1.name); // =>Jack;
console.log(box1.arr); // =>brother,sister;
box1.arr.push('father'); //
console.log(box1.arr); // =>brother,sister,father;
var box2 = obj(box);
console.log(box2.name); // =>Lee;
console.log(box2.arr); // =>brother,sister,father;引用類型共享了;
6.寄生式繼承?
// 把原型式+工廠模式結(jié)合而來(lái),目的是為了封裝創(chuàng)建對(duì)象的過(guò)程;
// 創(chuàng)建一個(gè)僅用于封裝繼承過(guò)程的函數(shù),
function create(o){ // 封裝創(chuàng)建過(guò)程;
var f = obj(o);
f.run = function(){
return this.arr; // 同樣會(huì)共享引用;
};
return f;
}
7.寄生組合式繼承?
// 之前說(shuō)過(guò),組合式繼承是JS最常用的繼承模式;
// 但是,組合式繼承也有問(wèn)題:
// 超類型在使用過(guò)程中會(huì)被調(diào)用兩次:一次是創(chuàng)建子類型的時(shí)候,另一次是在子類型構(gòu)造函數(shù)的內(nèi)部;
function Box(name){
this.name = name;
this.arr = ['brother','sister'];
}
Box.prototype.run = function(){
return this.name;
}
function Desk(name,age){
Box.call(this,name); // 第二次調(diào)用Box;
this.age = age;
}
Desk.prototype = new Box(); // 第一次調(diào)用Box;
// 寄生組合式繼承:
// 通過(guò)借用構(gòu)造函數(shù)來(lái)繼承屬性,
// 通過(guò)原型鏈的混成形式來(lái)繼承方法;
// 解決了兩次調(diào)用的問(wèn)題;
function obj(o){
function F(){};
F.prototype = o;
return new F();
}
function create(box,desk){
var f = obj(box.prototype);
f.constructor = desk;
desk.prototype = f;
}
function Box(name){
this.name = name;
this.arr = ['brother','sister'];
}
Box.prototype.run = function(){
return this.name;
}
function Desk(name,age){
Box.call(this,name);
this.age = age;
}
inheritPrototype(Box,Desk); // 通過(guò)這里實(shí)現(xiàn)繼承;
var desk = new Desk('Lee',100);
desk.arr.push('father');
console.log(desk.arr);
console.log(desk.run());
var desk2 = new Desk('Jack',200);
console.log(desk2.arr); // 兩次引用問(wèn)題解決;
四 小結(jié)
1.創(chuàng)建對(duì)象
對(duì)象可以在代碼執(zhí)行過(guò)程中創(chuàng)建和增強(qiáng),因此具有動(dòng)態(tài)性而非嚴(yán)格定義的實(shí)體;
在沒(méi)有類的情況下,可以采用下列模式創(chuàng)建對(duì)象;
(1).工廠模式:使用簡(jiǎn)單的函數(shù)創(chuàng)建對(duì)象,為對(duì)象添加屬性和方法,然后返回對(duì)象;
這個(gè)模式后來(lái)被構(gòu)造函數(shù)模式所取代;
(2).構(gòu)造函數(shù)模式:可以自定義引用類型,可以像創(chuàng)建內(nèi)置對(duì)象實(shí)例一眼使用new操作符;
缺點(diǎn):它的每個(gè)成員都無(wú)法得到復(fù)用,包括函數(shù);由于函數(shù)可以不局限于任何對(duì)象,因此沒(méi)有理由不在多個(gè)對(duì)象間共享函數(shù);
(3).原型模式:使用函數(shù)的prototype屬性來(lái)指定那些應(yīng)該共享的屬性和方法;
組合使用構(gòu)造函數(shù)模式和原型模式時(shí),使用構(gòu)造函數(shù)定義實(shí)例屬性,使用原型定義共享的屬性和方法;
2.原型鏈
原型鏈的構(gòu)建是通過(guò)將一個(gè)類型的實(shí)例賦值給另一個(gè)構(gòu)造函數(shù)的原型實(shí)現(xiàn)的;
子類型可以訪問(wèn)到超類型的所有屬性和方法;
原型鏈的問(wèn)題是對(duì)象實(shí)例共享所有繼承的屬性和方法,因此不適宜單獨(dú)使用;
解決方案:借用構(gòu)造函數(shù),即在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù);
這樣就可以做到每個(gè)實(shí)例都具有自己的屬性,同時(shí)還能保證只使用構(gòu)造函數(shù)來(lái)定義類型;
使用最多的繼承模式是組合繼承;它使用原型鏈繼承共享的屬性和方法,而通過(guò)借用構(gòu)造函數(shù)繼承實(shí)例屬性;
3.繼承模式
(1).原型式繼承:可以在不必預(yù)先定義構(gòu)造函數(shù)的情況下實(shí)現(xiàn)繼承;其本質(zhì)是執(zhí)行對(duì)給定對(duì)象的淺復(fù)制;
而復(fù)制得到的副本開(kāi)可以得到進(jìn)一步改造;
(2).寄生式繼承:基于某個(gè)對(duì)象或某些信息創(chuàng)建一個(gè)對(duì)象,然后增強(qiáng)對(duì)象,最后返回對(duì)象;
為了解決組合繼承模式由于多次調(diào)用超類型構(gòu)造函數(shù)而導(dǎo)致的低效率問(wèn)題,可以將這個(gè)模式與組合繼承一起使用;
(3).寄生組合式繼承:集寄生式繼承和組合式繼承的有點(diǎn)于一身,是實(shí)現(xiàn)基于類型繼承的最有效方式;
更多信息請(qǐng)查看IT技術(shù)專欄