欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript 繼承詳解及示例代碼

 更新時(shí)間:2016年09月06日 08:56:42   作者:Percy  
本文主要介紹JavaScript 繼承的知識(shí),這里整理了詳細(xì)的資料及簡(jiǎn)單示例代碼,幫助大家學(xué)習(xí)參考,有興趣的小伙伴可以參考下

有些知識(shí)當(dāng)時(shí)實(shí)在看不懂的話,可以先暫且放下,留在以后再看也許就能看懂了。

幾個(gè)月前,抱著《JavaScript 高級(jí)程序設(shè)計(jì)(第三版)》,啃完創(chuàng)建對(duì)象,就開(kāi)始啃起了 繼承 ,然而啃完 原型鏈 就實(shí)在是看不下去了,腦子越來(lái)越亂,然后就把它扔一邊了,繼續(xù)看后面的。現(xiàn)在利用這個(gè)暑假搞懂了這個(gè)繼承,就把筆記整理一下啦。

原型鏈(Prototype Chaining)

先看一篇文章,文章作者講的非常不錯(cuò),并且還配高清套圖哦。lol…

鏈接: [學(xué)習(xí)筆記](méi) 小角度看JS原型鏈

從原文中小摘幾句

  1. 構(gòu)造函數(shù)通過(guò) prototype 屬性訪問(wèn)原型對(duì)象
  2. 實(shí)例對(duì)象通過(guò) [[prototype]] 內(nèi)部屬性訪問(wèn)原型對(duì)象,瀏覽器實(shí)現(xiàn)了 proto 屬性用于實(shí)例對(duì)象訪問(wèn)原型對(duì)象
  3. 一切對(duì)象都是Object的實(shí)例,一切函數(shù)都是Function的實(shí)例
  4. Object 是構(gòu)造函數(shù),既然是函數(shù),那么就是Function的實(shí)例對(duì)象;Function是構(gòu)造函數(shù),但Function.prototype是對(duì)象,既然是對(duì)象,那么就是Object的實(shí)例對(duì)象

確定原型與實(shí)例的關(guān)系

有兩種方法來(lái)檢測(cè)原型與實(shí)例的關(guān)系:

instanceof :判斷該對(duì)象是否為另一個(gè)對(duì)象的實(shí)例

instanceof 內(nèi)部運(yùn)算機(jī)理如下:

functioninstance_of(L, R){//L 表示左表達(dá)式,R 表示右表達(dá)式
varO = R.prototype;// 取 R 的顯示原型
 L = L.__proto__; // 取 L 的隱式原型
while(true) {
if(L ===null)
returnfalse;
if(O === L)// 這里重點(diǎn):當(dāng) O 嚴(yán)格等于 L 時(shí),返回 true
returntrue;
 L = L.__proto__; 
 } 
}

上面代碼摘自: JavaScript instanceof 運(yùn)算符深入剖析

isPrototypeOf() :測(cè)試一個(gè)對(duì)象是否存在于另一個(gè)對(duì)象的原型鏈上
這兩個(gè)方法的不同點(diǎn)請(qǐng)參看: JavaScript isPrototypeOf vs instanceof usage

只利用原型鏈實(shí)現(xiàn)繼承

缺點(diǎn):1. 引用類(lèi)型值的原型屬性會(huì)被實(shí)例共享; 2. 在創(chuàng)建子類(lèi)型的實(shí)例時(shí),不能向超類(lèi)型的構(gòu)造函數(shù)中傳遞參數(shù)

functionFather(){
this.name ="father";
this.friends = ['aaa','bbb'];
}
functionSon(){
}
Son.prototype = newFather();
Son.prototype.constructor = Son;

vars1 =newSon();
vars2 =newSon();

console.log(s1.name);// father
console.log(s2.name);// father
s1.name = "son";
console.log(s1.name);// son
console.log(s2.name);// father

console.log(s1.friends);// ["aaa", "bbb"]
console.log(s2.friends);// ["aaa", "bbb"]
s1.friends.push('ccc','ddd');
console.log(s1.friends);// ["aaa", "bbb", "ccc", "ddd"]
console.log(s2.friends);// ["aaa", "bbb", "ccc", "ddd"]

只利用構(gòu)造函數(shù)實(shí)現(xiàn)繼承

實(shí)現(xiàn)方法:在子類(lèi)型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類(lèi)型構(gòu)造函數(shù)(使用 apply() 和 call() 方法)

優(yōu)點(diǎn):解決了原型中引用類(lèi)型屬性的問(wèn)題,并且子類(lèi)可以向超類(lèi)中傳參

缺點(diǎn):子類(lèi)實(shí)例無(wú)法訪問(wèn)父類(lèi)(超類(lèi))原型中定義的方法,所以函數(shù)復(fù)用就無(wú)從談起了。

functionFather(name,friends){
this.name = name;
this.friends = friends;
}
Father.prototype.getName = function(){
returnthis.name;
};

functionSon(name){
// 注意: 為了確保 Father 構(gòu)造函數(shù)不會(huì)重寫(xiě) Son 構(gòu)造函數(shù)的屬性,請(qǐng)將調(diào)用 Father 構(gòu)造函數(shù)的代碼放在 Son 中定義的屬性的前面。
 Father.call(this,name,['aaa','bbb']);

this.age =22;
}

vars1 =newSon('son1');
vars2 =newSon('son2');

console.log(s1.name);// son1
console.log(s2.name);// son2

s1.friends.push('ccc','ddd');
console.log(s1.friends);// ["aaa", "bbb", "ccc", "ddd"]
console.log(s2.friends);// ["aaa", "bbb"]

// 子類(lèi)實(shí)例無(wú)法訪問(wèn)父類(lèi)原型中的方法
s1.getName(); // TypeError: s1.getName is not a function
s2.getName(); // TypeError: s2.getName is not a function

組合繼承(Combination Inheritance)

實(shí)現(xiàn)方法:使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承,而通過(guò)借用構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承。

functionFather(name,friends){
this.name = name;
this.friends = friends;
}
Father.prototype.money = "100k $";
Father.prototype.getName = function(){
console.log(this.name);
};

functionSon(name,age){
// 繼承父類(lèi)的屬性
 Father.call(this,name,['aaa','bbb']);

this.age = age;
}

// 繼承父類(lèi)原型中的屬性和方法
Son.prototype = newFather();
Son.prototype.constructor = Son;

Son.prototype.getAge = function(){
console.log(this.age);
};

vars1 =newSon('son1',12);
s1.friends.push('ccc');
console.log(s1.friends);// ["aaa", "bbb", "ccc"]
console.log(s1.money);// 100k $
s1.getName(); // son1
s1.getAge(); // 12

vars2 =newSon('son2',24);
console.log(s2.friends);// ["aaa", "bbb"]
console.log(s2.money);// 100k $
s2.getName(); // son2
s2.getAge(); // 24

組合繼承避免了單方面使用原型鏈或構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)繼承的缺陷,融合了它們的優(yōu)點(diǎn),成為 JavaScript 中最常用的繼承模式,但是它也是有缺陷的,組合繼承的缺陷會(huì)在后面專(zhuān)門(mén)提到。

原型式繼承(Prototypal Inheritance)

實(shí)現(xiàn)思路:借助原型基于已有的對(duì)象創(chuàng)建新對(duì)象,同時(shí)不必因此而創(chuàng)建自定義類(lèi)型。

為了達(dá)到這個(gè)目的,引入了下面的函數(shù)(obj)

functionobj(o){
functionF(){}
 F.prototype = o;
returnnewF();
}
varperson1 = {
 name: "percy",
 friends: ['aaa','bbb']
};
varperson2 = obj(person1);
person2.name = "zyj";
person2.friends.push('ccc');

console.log(person1.name);// percy
console.log(person2.name);// zyj
console.log(person1.friends);// ["aaa", "bbb", "ccc"]
console.log(person2.friends);// ["aaa", "bbb", "ccc"]
ECMAScript 5 通過(guò)新增 Object.create() 方法規(guī)范化了原型式繼承。在傳入一個(gè)參數(shù)的情況下, Object.create() 和 obj() 方法的行為相同。

varperson1 = {
 name: "percy",
 friends: ['aaa','bbb']
};
varperson2 =Object.create(person1);
person2.name = "zyj";
person2.friends.push('ccc');

console.log(person1.name);// percy
console.log(person2.name);// zyj
console.log(person1.friends);// ["aaa", "bbb", "ccc"]
console.log(person2.friends);// ["aaa", "bbb", "ccc"]

在沒(méi)有必要興師動(dòng)眾地創(chuàng)建構(gòu)造函數(shù),而只想讓一個(gè)對(duì)象與另一個(gè)對(duì)象保持類(lèi)似的情況下,可以選擇使用這種繼承。

寄生式繼承(Parasitic Inheritance)

寄生式繼承是與原型式繼承緊密相關(guān)的一種思路。

實(shí)現(xiàn)思路:創(chuàng)建一個(gè)僅僅用于封裝繼承過(guò)程的函數(shù),該函數(shù)在內(nèi)部以某種方式來(lái)增強(qiáng)對(duì)象,最后再返回對(duì)象。

functionobj(o){
functionF(){}
 F.prototype = o;
returnnewF();
}
functioncreatePerson(original){// 封裝繼承過(guò)程
varclone = obj(original);// 創(chuàng)建對(duì)象
 clone.showSomething = function(){// 增強(qiáng)對(duì)象
console.log("Hello world!");
 };
returnclone;// 返回對(duì)象
}

varperson = {
 name: "percy"
};
varperson1 = createPerson(person);
console.log(person1.name);// percy
person1.showSomething(); // Hello world!

寄生組合式繼承(Parasitic Combination Inheritance)

先來(lái)說(shuō)說(shuō)我們前面的組合繼承的缺陷。 組合繼承最大的問(wèn)題就是無(wú)論什么情況下,都會(huì)調(diào)用兩次父類(lèi)的構(gòu)造函數(shù):一次是創(chuàng)建子類(lèi)的原型的時(shí)候,另一次是在調(diào)用子類(lèi)構(gòu)造函數(shù)的時(shí)候,在子類(lèi)構(gòu)造函數(shù)內(nèi)部又調(diào)用了父類(lèi)的構(gòu)造函數(shù)。

functionFather(name,friends){
this.name = name;
this.friends = friends;
}
Father.prototype.money = "100k $";
Father.prototype.getName = function(){
console.log(this.name);
};

functionSon(name,age){
// 繼承父類(lèi)的屬性
 Father.call(this,name,['aaa','bbb']);// 第二次調(diào)用 Father() , 實(shí)際是在 new Son() 時(shí)才會(huì)調(diào)用

this.age = age;
}

// 繼承父類(lèi)原型中的屬性和方法
Son.prototype = newFather();// 第一次調(diào)用 Father()
Son.prototype.constructor = Son;

第一次調(diào)用使的子類(lèi)的原型成了父類(lèi)的一個(gè)實(shí)例,從而子類(lèi)的原型得到了父類(lèi)的實(shí)例屬性;第二次調(diào)用會(huì)使得子類(lèi)的實(shí)例也得到了父類(lèi)的實(shí)例屬性;而子類(lèi)的實(shí)例屬性默認(rèn)會(huì)屏蔽掉子類(lèi)原型中與其重名的屬性。所以,經(jīng)過(guò)這兩次調(diào)用, 子類(lèi)原型中出現(xiàn)了多余的的屬性 ,從而引進(jìn)了寄生組合式繼承來(lái)解決這個(gè)問(wèn)題。

寄生組合式繼承的背后思路是: 不必為了指定子類(lèi)的原型而調(diào)用父類(lèi)的構(gòu)造函數(shù),我們所需要的無(wú)非就是父類(lèi)原型的一個(gè)副本而已 。

本質(zhì)上,就是使用寄生式繼承來(lái)繼承父類(lèi)的原型,然后將結(jié)果返回給子類(lèi)的原型。

functionobj(o){
functionF(){}
 F.prototype = o;
returnnewF();
}
functioninheritPrototype(son,father){
varprototype = obj(father.prototype);// 創(chuàng)建對(duì)象
 prototype.constructor = son; // 增強(qiáng)對(duì)象
 son.prototype = prototype; // 返回對(duì)象
}
functionFather(name,friends){
this.name = name;
this.friends = friends;
}
Father.prototype.money = "100k $";
Father.prototype.getName = function(){
console.log(this.name);
};

functionSon(name,age){
// 繼承父類(lèi)的屬性
 Father.call(this,name,['aaa','bbb']);

this.age = age;
}

// 使用寄生式繼承繼承父類(lèi)原型中的屬性和方法
inheritPrototype(Son,Father);

Son.prototype.getAge = function(){
console.log(this.age);
};

vars1 =newSon('son1',12);
s1.friends.push('ccc');
console.log(s1.friends);// ["aaa", "bbb", "ccc"]
console.log(s1.money);// 100k $
s1.getName(); // son1
s1.getAge(); // 12

vars2 =newSon('son2',24);
console.log(s2.friends);// ["aaa", "bbb"]
console.log(s2.money);// 100k $
s2.getName(); // son2
s2.getAge(); // 24

優(yōu)點(diǎn):使子類(lèi)原型避免了繼承父類(lèi)中不必要的實(shí)例屬性。

開(kāi)發(fā)人員普遍認(rèn)為寄生組合式繼承是實(shí)現(xiàn)基于類(lèi)型繼承的最理想的繼承方式。

最后

最后,強(qiáng)烈推薦兩篇很硬的文章

Javascript – How Prototypal Inheritance really works
JavaScript's Pseudo Classical Inheritance diagram (需要翻墻)

摘第二篇文章的一張硬圖過(guò)來(lái):


看完之后,秒懂原型鏈,有木有?

以上就是對(duì)JavaScript 繼承的資料整理,后續(xù)繼續(xù)補(bǔ)充相關(guān)資料謝謝大家對(duì)本站的支持!

相關(guān)文章

  • 前端js彈出框組件使用方法

    前端js彈出框組件使用方法

    這篇文章主要為大家詳細(xì)介紹了前端js彈出框組件的使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • js left,right,mid函數(shù)

    js left,right,mid函數(shù)

    在JAVASCRIPT中LEFT,RIGHT,MID函數(shù)的等價(jià)函數(shù),非常適合經(jīng)常用寫(xiě)asp的朋友
    2008-06-06
  • JS中遞歸函數(shù)

    JS中遞歸函數(shù)

    編程語(yǔ)言中,函數(shù)Func(Type a,……)直接或間接調(diào)用函數(shù)本身,則該函數(shù)稱(chēng)為遞歸函數(shù)。遞歸函數(shù)不能定義為內(nèi)聯(lián)函數(shù)。這篇文章主要介紹了JS中遞歸函數(shù)的相關(guān)資料,需要的朋友可以參考下
    2016-06-06
  • JavaScript實(shí)現(xiàn)點(diǎn)擊文字切換登錄窗口的方法

    JavaScript實(shí)現(xiàn)點(diǎn)擊文字切換登錄窗口的方法

    這篇文章主要介紹了JavaScript實(shí)現(xiàn)點(diǎn)擊文字切換登錄窗口的方法,涉及javascript操作div層及相關(guān)樣式的技巧,需要的朋友可以參考下
    2015-05-05
  • 時(shí)間處理工具?dayjs使用示例詳解

    時(shí)間處理工具?dayjs使用示例詳解

    這篇文章主要為大家介紹了時(shí)間處理工具?dayjs使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 如何使用Bootstrap創(chuàng)建表單

    如何使用Bootstrap創(chuàng)建表單

    在本章中,我們將學(xué)習(xí)如何使用 Bootstrap 創(chuàng)建表單。Bootstrap 通過(guò)一些簡(jiǎn)單的 HTML 標(biāo)簽和擴(kuò)展的類(lèi)即可創(chuàng)建出不同樣式的表單
    2017-03-03
  • 關(guān)于微信小程序map組件z-index的層級(jí)問(wèn)題分析

    關(guān)于微信小程序map組件z-index的層級(jí)問(wèn)題分析

    這篇文章主要給大家介紹了關(guān)于微信小程序map組件z-index的層級(jí)問(wèn)題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用微信小程序具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • setTimeout()與setInterval()方法區(qū)別介紹

    setTimeout()與setInterval()方法區(qū)別介紹

    計(jì)時(shí)器setTimeout()和setInterval()兩個(gè)都是js的計(jì)時(shí)功能的函數(shù)兩個(gè)有些區(qū)別,下面為大家簡(jiǎn)單介紹下,希望對(duì)大家有所幫助
    2013-12-12
  • 解決JS外部文件中文注釋出現(xiàn)亂碼問(wèn)題

    解決JS外部文件中文注釋出現(xiàn)亂碼問(wèn)題

    中文亂碼在Java Web開(kāi)發(fā)中經(jīng)常出現(xiàn),這是由于不同的部分編碼不一樣造成的,一般在開(kāi)發(fā)中,我們把所有能設(shè)編碼的地方,全部設(shè)置成UTF-8,但是有時(shí)候還是會(huì)出現(xiàn)亂碼的情況。下面通過(guò)本文給大家分享JS外部文件中文注釋出現(xiàn)亂碼的解決方案,一起看看吧
    2017-07-07
  • JS、jquery實(shí)現(xiàn)幾分鐘前、幾小時(shí)前、幾天前等時(shí)間差顯示效果的代碼實(shí)例分享

    JS、jquery實(shí)現(xiàn)幾分鐘前、幾小時(shí)前、幾天前等時(shí)間差顯示效果的代碼實(shí)例分享

    在新浪微博首頁(yè)看到每條微博后邊顯示的時(shí)間并不是標(biāo)準(zhǔn)的年-月-日格式,而是經(jīng)過(guò)換算的時(shí)間差,如:發(fā)表于5分鐘前、發(fā)表于“2小時(shí)前”,比起標(biāo)準(zhǔn)的時(shí)間顯示格式,貌似更加直觀和人性化
    2014-04-04

最新評(píng)論