国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JavaScript由淺及深敲開原型鏈(二)

Carbs / 1652人閱讀

摘要:不然原型鏈會(huì)斷開。喵喵喵這樣會(huì)使上一條語句失效,從而使原型鏈斷開。這是在原型鏈里面無法做到的一個(gè)功能。屬性使用借用構(gòu)造函數(shù)模式,而方法則使用原型鏈。

一、對(duì)象的繼承 1.了解原型鏈

在上一篇我們講過關(guān)于原型對(duì)象的概念,當(dāng)然如果不了解的建議去翻看第一篇文章,文末附有連接。我們知道每個(gè)對(duì)象都有各自的原型對(duì)象,那么當(dāng)我們把一個(gè)對(duì)象的實(shí)例當(dāng)做另外一個(gè)對(duì)象的原型對(duì)象。。這樣這個(gè)對(duì)象就擁有了另外一個(gè)引用類型的所有方法與屬性,當(dāng)我們?cè)侔言搶?duì)象的實(shí)例賦予另一個(gè)原型對(duì)象時(shí),這樣又把這些方法繼承下去。如此層層遞進(jìn),對(duì)象與原型間存在鏈接關(guān)系,這樣就構(gòu)成了原型鏈

function Animal(){
    this.type = "Animal";
}

Animal.prototype.say = function(){
    console.log(this.type);
}

function Cat(){
    this.vioce = "喵喵喵";
}

Cat.prototype = new Animal();

Cat.prototype.shout = function(){
    console.log(this.vioce);
}

let cat1 = new Cat();
cat1.say();     //"Animal"

//當(dāng)然,我們還可以繼續(xù)繼承下去

function Tom(){
    this.name = "Tom";
}

Tom.prototype = new Cat();

Tom.prototype.sayName = function(){
    console.log(this.name);
}

let cat2 = new Tom();
cat2.say();     //"Animal"
cat2.shout();   //"喵喵喵"
cat2.sayName();     //"Tom"
cat1.sayName();     //err 報(bào)錯(cuò)表示沒有該函數(shù)

很神奇的,原型鏈就實(shí)現(xiàn)了對(duì)象的繼承。使用原型鏈就可以使一個(gè)新對(duì)象擁有之前對(duì)象的所有方法和屬性。至于cat1.sayName()會(huì)報(bào)錯(cuò),是因?yàn)樵摲椒ㄊ窃谒淖釉蛯?duì)象中定義,所以無法找到該函數(shù)。但是我相信很多人看到這里還是會(huì)一頭霧水,到底鏈在哪里了?誰和誰鏈在一起了?我用一張圖來讓大家更好的理解這個(gè)。

咋眼一看,這張圖信息量不少,但是理解起來卻一點(diǎn)都不難。我們先從Animal看起,Animal中存在一個(gè)prototype指向其原型對(duì)象,這一部分應(yīng)該沒什么問題。但是Animal原型對(duì)象中卻存在[[prototype]]指向了Object,實(shí)際上是指向了Object.prototype這是因?yàn)樗泻瘮?shù)都是從Object繼承而來的所有函數(shù)都是Object的實(shí)例。這也正是所有的函數(shù)都可以擁有Object方法的原因,如toString()。所以這也是原型鏈的一部分,我們從創(chuàng)建自定義類型開始就已經(jīng)踏入了原型鏈中。

但是這部分我們暫且不管它,我們繼續(xù)往下面看。我們把Animal的實(shí)例當(dāng)做Cat的原型對(duì)象

Cat.prototype = new Animal();

這樣Cat實(shí)例就擁有了其父類型的所有方法與屬性。因?yàn)榇a中尋找一個(gè)方法會(huì)不斷往上找,先在實(shí)例中尋找,如果沒有就在原型對(duì)象中去尋找,假如原型對(duì)象中沒有,就會(huì)往原型對(duì)象的原型對(duì)象中去找,如此遞進(jìn),最終如果找到則返回,找不到則報(bào)錯(cuò)。當(dāng)我們構(gòu)成原型鏈時(shí),會(huì)有一個(gè)對(duì)象原型當(dāng)做其父類型的實(shí)例,這樣便形成一條原型鏈。當(dāng)然,如果現(xiàn)在有不明白 [[prototype]] (__proto__)與prototype的區(qū)別可以去翻看我們第一篇文章,在這就不重復(fù)了。

這樣一來我們便明白了為何cat1中沒有sayName函數(shù)并了解原型鏈如何實(shí)現(xiàn)繼承了。但是我又提出了一個(gè)問題,假如我們把給子類型原型對(duì)象定義方法的位置調(diào)換一下,那么會(huì)發(fā)生什么事呢?

function Animal(){
    this.type = "Animal";
}

Animal.prototype.say = function(){
    console.log(this.type);
}

function Cat(){
    this.vioce = "喵喵喵";
}

Cat.prototype.shout = function(){
    console.log(this.vioce);
}

Cat.prototype = new Animal();

let cat1 = new Cat();
cat1.say();     //"Animal"
cat1.shuot();       //err,報(bào)錯(cuò)無此函數(shù)

控制臺(tái)中會(huì)毫不留情的告訴你,沒有該方法Uncaught TypeError: cat1.shuot is not a function。這是因?yàn)楫?dāng)你把父類的實(shí)例賦給子類原型對(duì)象時(shí),會(huì)將其替換。那么你之前所定義的方法就會(huì)失效。所以在這里要注意的一點(diǎn)就是:給原型添加方法時(shí)一定要在替換原型語句之后,而且還有一點(diǎn)要注意就是,在用原型鏈實(shí)現(xiàn)繼承的時(shí)候,千萬不可以用字面量形式定義原型方法。不然原型鏈會(huì)斷開。

function Animal(){
    this.type = "Animal";
}

Animal.prototype.say = function(){
    console.log(this.type);
}

function Cat(){
    this.vioce = "喵喵喵";
}

Cat.prototype = new Animal();

Cat.prototype = {       //這樣會(huì)使上一條語句失效,從而使原型鏈斷開。
    shout:function(){
        console.log(this.vioce);
    }
}
2.原型鏈的問題

接下來我們談?wù)勗玩湹膯栴}。說起原型鏈的問題我們大概可以聯(lián)想到原型對(duì)象的問題:其屬性與方法會(huì)被所有實(shí)例共享,那么在原型鏈中亦是如此。

function Animal(){
    this.type = "Animal";
    this.color = ["white","black","yellow"];
}

Animal.prototype.say = function(){
    console.log(this.type);
}

function Cat(){
    this.vioce = "喵喵喵";
}

Cat.prototype = new Animal();

Cat.prototype.shout = function(){
    console.log(this.vioce);
}

let cat1 = new Cat();
let cat2 = new Cat();
cat1.say();     //"Animal"
cat1.say();     //"Animal"
cat1.color.push("pink");

console.log(cat1.color);    //["white", "black", "yellow", "pink"]
console.log(cat2.color);    //["white", "black", "yellow", "pink"]

當(dāng)然,這也好理解不是。倘若孫子教會(huì)了爺爺某件事,那么爺爺會(huì)把他的本領(lǐng)傳個(gè)他的每個(gè)兒子孫子,沒毛病對(duì)吧。但是我們想要的是,孫子自己學(xué)會(huì)某件事,但不想讓其他人學(xué)會(huì)。這樣意思就是每個(gè)實(shí)例擁有各自的屬性,不與其他實(shí)例共享。那么我們就引入了借用構(gòu)造函數(shù)的概念了。

3.借用構(gòu)造函數(shù)

借用構(gòu)造函數(shù),簡(jiǎn)單來說就是在子類構(gòu)造函數(shù)里面調(diào)用父類的構(gòu)造函數(shù)。要怎么調(diào)用?可以使用到apply()call()這些方法來實(shí)現(xiàn)這個(gè)功能。

function Animal(type = "Animal"){       //設(shè)置一個(gè)參數(shù),如果子類不傳入?yún)?shù)則默認(rèn)為"Animal"
    this.type = type;
    this.color = ["white","black","yellow"];
}

function Cat(type){
    Animal.call(this,type);     //繼承Animal同時(shí)傳入type,也可以不傳參
}

let cat1 = new Cat();           //沒有傳參,type默認(rèn)為"Animal"
let cat2 = new Cat("Cat");      //傳入"Cat",type則為"Cat"

cat1.color.push("pink");


console.log(cat1.color);    //["white", "black", "yellow", "pink"]
console.log(cat2.color);    //["white", "black", "yellow"]
console.log(cat1.type);     //"Animal"
console.log(cat2.type);     //"Cat"

這樣就實(shí)現(xiàn)了實(shí)例屬性不共享的功能,而且我們?cè)谶@個(gè)里面還可以傳入一個(gè)參數(shù),讓其向父類傳參。這是在原型鏈里面無法做到的一個(gè)功能。至于call()apply()方法,在這暫且不展開,日后另作文章闡明。暫且只需要知道這是改變函數(shù)作用域的就行。

那么,借用構(gòu)造函數(shù)的問題也就是構(gòu)造函數(shù)的問題,方法都定義在構(gòu)造函數(shù)里面了,復(fù)用性就基本涼涼。所以,我們要組合起來使用。屬性使用借用構(gòu)造函數(shù)模式而方法則使用原型鏈

4.組合繼承
function Animal(){
    this.type = "Animal";
    this.color = ["white","black","yellow"];
}

Animal.prototype.say = function(){
    console.log(this.type);
}

function Cat(){
    Animal.call(this);      //繼承屬性
    
    this.vioce = "喵喵喵";
    
}

Cat.prototype = new Animal();       //繼承方法

Cat.prototype.shout = function(){
    console.log(this.vioce);
}

let cat1 = new Cat();
let cat2 = new Cat();
cat1.say();     //"Animal"
cat1.say();     //"Animal"
cat1.color.push("pink");

console.log(cat1.color);    //["white", "black", "yellow", "pink"]
console.log(cat2.color);    //["white", "black", "yellow"]

這一套方法也變成了最常用的繼承方法了。但是其中也是有個(gè)缺陷,就是每次都會(huì)調(diào)用兩次父類的構(gòu)造函數(shù)。從而使得實(shí)例中與原型對(duì)象中創(chuàng)造相同的屬性,不過原型對(duì)象中的值卻毫無意義。那有沒有更完美的方法?有,就是寄生組合式繼承。在這里我就放代碼給大家。

function obj(o){
    function F(){}
    F.prototype = o;
    return new F();
}

function inheritPrototype(sub,super){
    let prototype = obj(super.prototype);       //相當(dāng)于拷貝了一個(gè)父類對(duì)象
    prototype.constructor = sub;    增強(qiáng)對(duì)象
    sub.prototype = prototype;      指定對(duì)象
}
function Animal(){
    this.type = "Animal";
    this.color = ["white","black","yellow"];
}

Animal.prototype.say = function(){
    console.log(this.type);
}

function Cat(){
    Animal.call(this);      //繼承屬性
    
    this.vioce = "喵喵喵";
    
}

inheritPrototype(Cat,Animal);

Cat.prototype.shout = function(){
    console.log(this.vioce);
}

let cat1 = new Cat();
let cat2 = new Cat();
cat1.say();     //"Animal"
cat1.say();     //"Animal"
cat1.color.push("pink");

console.log(cat1.color);    //["white", "black", "yellow", "pink"]
console.log(cat2.color);    //["white", "black", "yellow"]

這樣通過一個(gè)巧妙的方法就可以少調(diào)用一次父類的構(gòu)造函數(shù),而且不會(huì)賦予原型對(duì)象中無意義的屬性。這是被認(rèn)為最理想的繼承方法。但是最多人用的還是上面那個(gè)組合式繼承方法。

總結(jié)

到這原型鏈的基本概念與用法都已經(jīng)一一講述,我們需要注意的地方就是prototype__proto__的關(guān)系,重點(diǎn)是分清其中的區(qū)別,了解父類型跟其子類型的關(guān)系,他們之間的聯(lián)系在哪。大概要弄懂的地方,就是要把那兩文章的兩張圖吃透,那么我們就已經(jīng)把原型鏈吃透大半了。

最后倘若大家還有什么不懂的地方,或者博主有什么遺漏的地方,歡迎大家指出交流。如有興趣可以持續(xù)關(guān)注本博主。

原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/94649.html

相關(guān)文章

  • JavaScript由淺及深了解原型鏈(一)

    摘要:但是該方法有個(gè)缺點(diǎn)就是看不出該對(duì)象的類型,于是乎構(gòu)造函數(shù)模式應(yīng)運(yùn)而生。當(dāng)然,如果細(xì)心的朋友應(yīng)該會(huì)發(fā)現(xiàn)函數(shù)名首字母大寫了,這是約定在構(gòu)造函數(shù)時(shí)將首字母大寫。這時(shí)候,聰明的人應(yīng)該都可以想到,將構(gòu)造函數(shù)模式和原型模式組合起來就可以了。 一.什么是js對(duì)象 1.簡(jiǎn)單理解js對(duì)象 在了解原型鏈之前,我們先要弄清楚什么是JavaScript的對(duì)象,JavaScript對(duì)象又由哪些組成。有人說一個(gè)程...

    YorkChen 評(píng)論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.16 - 淺入淺出 JavaScript 函數(shù)式編程

    摘要:函數(shù)式編程,一看這個(gè)詞,簡(jiǎn)直就是學(xué)院派的典范。所以這期周刊,我們就重點(diǎn)引入的函數(shù)式編程,淺入淺出,一窺函數(shù)式編程的思想,可能讓你對(duì)編程語言的理解更加融會(huì)貫通一些。但從根本上來說,函數(shù)式編程就是關(guān)于如使用通用的可復(fù)用函數(shù)進(jìn)行組合編程。 showImg(https://segmentfault.com/img/bVGQuc); 函數(shù)式編程(Functional Programming),一...

    csRyan 評(píng)論0 收藏0
  • JavaScript 異步

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。寫一個(gè)符合規(guī)范并可配合使用的寫一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問題描述 在開發(fā)過程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過...

    tuniutech 評(píng)論0 收藏0
  • 區(qū)塊鏈概念 That You Must Know 第四期(2)

    摘要:下圖給出一個(gè)簡(jiǎn)單的列表圖什么是哈希和哈希值為理解挖礦的代碼機(jī)制,首先解決幾個(gè)概念。第一個(gè)就是哈希。哈希值為十六進(jìn)制表示的數(shù),且長(zhǎng)度固定。也正是哈希值的這些特點(diǎn),賦予了其加密信息時(shí)更高的安全性。 第四期 挖礦的相關(guān)算法(2) 卡酷少Wechat:13260325501 看過(1)篇,相信你一定對(duì)挖礦的機(jī)制有了一點(diǎn)了解。那么本篇,我們來一起看一下挖礦中涉及的算法。 在本篇文章中,如果在...

    Sourcelink 評(píng)論0 收藏0
  • 移除注釋的完善思路:真的可以用正則實(shí)現(xiàn)?

    摘要:導(dǎo)語網(wǎng)上有很多自稱能實(shí)現(xiàn)移除注釋的正則表達(dá)式,實(shí)際上存在種種缺陷。為了避免正則的記憶功能,都使用了正則字面量進(jìn)行測(cè)試。下面是去除單行注釋的最終代碼。修改方式將刪除注釋的正則改為。無法正確的移除引號(hào)塊。 導(dǎo)語 網(wǎng)上有很多自稱能實(shí)現(xiàn)移除JS注釋的正則表達(dá)式,實(shí)際上存在種種缺陷。這使人多少有些愕然,也不禁疑惑到:真的可以用正則實(shí)現(xiàn)嗎?而本篇文章以使用正則移除JS注釋為目標(biāo),通過實(shí)踐,由淺及深...

    WalkerXu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<