關(guān)于Android工程師轉(zhuǎn)vue的三兩事兒(10)--原型與原型鏈

說起原型和原型鏈接描扯,著實讓我這個前端菜鳥胡搞了好一陣子。雖然有點繞口的緣故趟薄,但是更多的還是自己比較浮躁帶來的后果绽诚,這一塊據(jù)說是前端的基礎(chǔ),看了很多遍才差不多有點頭目杭煎。分享一下我領(lǐng)悟到的武林秘籍恩够,希望能給您帶來一點啟迪,如果存在任何問題羡铲,請及時指正我蜂桶,謝謝。????????

一也切、 淺談數(shù)據(jù)屬性和訪問器屬性

1. 創(chuàng)建對象:

通常創(chuàng)建對象一般都會有兩種方法:

//利用object來創(chuàng)建對象
var person = new Person();
person.name = "klivitam";
person.age  = 23;

person.sayName = function(){
  alert(this.name)
}
// 對象字面量法扑媚,推薦使用這種方法
var person = {
  name:"klivitam",
  age:23,
  
  sayName: function(){
    alert(this.name);
  }
}

2. 屬性類型

在javascript中腰湾,對象的屬性一共分為兩種:數(shù)據(jù)屬性和訪問器屬性。

  • 數(shù)據(jù)屬性
    configurable:表示能否通過delete刪除屬性從而重新定義屬性疆股,能否修改屬性的特性费坊,或能否把屬性修改為訪問器屬性,默認(rèn)為true
    enumerable:表示能否通過for-in循環(huán)返回屬性
    writable:表示能否修改屬性的值
    value:包含該屬性的數(shù)據(jù)值押桃。默認(rèn)為undefined
    數(shù)據(jù)屬性包含一個數(shù)據(jù)值的位置葵萎,在這個位置可以讀取和寫入值。以上就是描述數(shù)據(jù)值行為的四個特性唱凯。
    okey羡忘,可能全憑著口述概念無法了解這個意思,現(xiàn)在就實操代碼吧磕昼。
// "use strict"
var worker = {}
Object.defineProperty(worker, "job", {
    writable: false,
    value: "碼農(nóng)"
})
console.log(worker.job)
worker.job = "教師"
console.log(worker.job)
writable=false

當(dāng)把writable的屬性改成true的時候卷雕,


writable = true

從上面的代碼可以看出來writable是用來控制是否能修改屬性的值。另外當(dāng)writable為false的時候票从,并且使用嚴(yán)格模式下漫雕,會發(fā)生:
嚴(yán)格模式下,writable為false的時候修改值會報錯

// "use strict"
var worker = {}
Object.defineProperty(worker, "job", {
    // writable: false,
    configurable:false,
    value: "碼農(nóng)"
})
console.log(worker.job)
delete(worker.job)
console.log(worker.job)

當(dāng)configurable為false的時候峰鄙,使用delete方法會失效浸间,并且在嚴(yán)格模式下,delete會報錯吟榴。同理改成true的時候,則為undefined魁蒜,說明刪除成功了。

configurable為false
configurable為true
注意:當(dāng)value的值沒初始化的時候吩翻,默認(rèn)放置undefined


至于最后一個我覺得就沒必要代碼進(jìn)行演示了兜看,同理可得。


特征默認(rèn)值
  • 訪問器屬性
    configurable:表示能否通過delete刪除屬性從而重新定義屬性狭瞎,能否修改屬性的特性细移,或能否把屬性修改為訪問器屬性,默認(rèn)為false
    enumerable:表示能否通過for-in循環(huán)返回屬性,默認(rèn)為false
    Get:在讀取屬性時調(diào)用的函數(shù),默認(rèn)值為undefined
    Set:在寫入屬性時調(diào)用的函數(shù),默認(rèn)值為undefined
    訪問器屬性不包含數(shù)據(jù)值熊锭,包含的是一對get和set方法弧轧,在讀寫訪問器屬性時,就是通過這兩個方法來進(jìn)行操作處理的碗殷。并且訪問器屬性不能直接定義精绎,要通過Object.defineProperty()這個方法來定義。
    直接上代碼吧:
var worker = {
    _job:"碼農(nóng)",
    age: 23
}
Object.defineProperty(worker,"job",{
    get:function(){
        return this._job;
    },
    set:function(newJob){
        if(newJob!==this._job){
            this._job = newJob;
            this.age ++
        }
    }
})
console.log(Object.getOwnPropertyDescriptor(worker,"job"));
console.log(worker.job)
worker.job = "教師"
console.log(worker.job)
console.log("更換職業(yè)就變老一年亿扁,5555~:"+worker.age)
現(xiàn)實的實例

二捺典、 js設(shè)計模式

1、 工廠模式

工廠模式是一個很基礎(chǔ)的一個模式吧从祝,反正我在學(xué)java (android)的時候經(jīng)常會遇到這種模式襟己,主要是抽象了創(chuàng)建對象的具體過程引谜。具體的代碼如下:

//屌絲程序員,只能偶爾意淫一哈 = l =,別噴我 
function addBeatiGrilWx(name,age,job){
    var gril = new Object();
    gril.name = name;
    gril.age = age;
    gril.job = job;
    gril.sayHi = function(){
        console.log("hi! " + this.name)
    };
    return gril
}
var lyf = addBeatiGrilWx("liuyifei",18,"actor");
lyf.sayHi();
console.log(lyf);

效果如下
工廠模式效果圖

工廠模式雖然解決了創(chuàng)建多個相似對象的問題擎浴,但是卻沒有解決對象識別的問題(即不清楚一個對象的類型)员咽,于是出現(xiàn)了構(gòu)造函數(shù)模式。

2贮预、 構(gòu)造函數(shù)模式

構(gòu)造函數(shù)可以用來創(chuàng)造特定類型的對象贝室。具體的代碼如下

function BeautiGril(name,age,photo){
    this.name = name;
    this.age = age;
    this.photo = photo;
    this.sayHi = function(){
        console.log("hi! "+this.name)
    }
}
var lyf = new BeautiGril("liuyifei",18,"baidu");
lyf.sayHi();
console.log(lyf)
console.log(lyf.constructor == BeautiGril)
console.log(lyf instanceof BeautiGril)
console.log(lyf instanceof Object)

具體的效果如下:
效果圖

創(chuàng)建自定義的構(gòu)造函數(shù)意味著將來可以將它的實例標(biāo)識為一種特定的類型,這也是前面提到他相較于工廠模式的優(yōu)勢仿吞。
構(gòu)造函數(shù)模式看似很好滑频,但是也存在一個問題,就拿上面的代碼來說如果我創(chuàng)建多個實例唤冈,不止lyf(畢竟還是想多要幾個小姐姐的 咳咳)一個峡迷。而此時sayHi這個公共的方法就會被多次重復(fù)創(chuàng)建。這樣其實不太可取的你虹,如果把sayHi方法放置出去绘搞,

function BeautiGril(name,age,photo){
    this.name = name;
    this.age = age;
    this.photo = photo;

}
function sayHi(){
    console.log("hi! "+this.name)
}

那么相當(dāng)新建了一個全局方法,這樣豈不是更加的沒有必要了么傅物?此時就要引入到原型模式了夯辖。

3. 原型模式

我們創(chuàng)建的函數(shù)都有prototype(原型)屬性,這個屬性是指針董饰,指向一個對象蒿褂,而這個對象的用途是包含由特定類型的所有實例所共享的屬性和方法,使用原型對象就可以讓所有實例對象均包含這些屬性及方法尖阔。

function Worker(){}
Worker.prototype.name = "programmer";
Worker.prototype.work = "programming...";
Worker.prototype.heartSound = function(){
    console.log(this.name+" want rest,but he still "+this.work)
}

var xiaoZhang = new Worker();
xiaoZhang.heartSound();

var xiaoWang = new Worker();
xiaoWang.heartSound();

console.log(xiaoZhang.heartSound ==xiaoWang.heartSound)

這里我還是說一下贮缅,我將heartSound()方法和所有的屬性直接添加到了Woker的原型屬性中榨咐,然后通過new創(chuàng)建對象介却,在原型模式中這些屬性和方法對于所有的實例是共享的。
但是這里存在有點問題--那就是并不是所有的worker都是程序員块茁。這就引發(fā)了最后一種模式的混用齿坷。

3. 原型模式+構(gòu)造器模式

這個模式在我的理解上來說,主要是為了避免單獨用原型模式所帶來弊病数焊,就拿上一份代碼來說永淌,并不是所有的worker都是程序員,如果想一個醫(yī)生想去復(fù)用這個類的時候佩耳,就必須改變其原型上的值遂蛀,如果改變其原型的值,那么整個都會亂套了干厚。于是我想到構(gòu)造器模式

function Worker(name,work){
    this.name = name;
    this.work = work;
}
Worker.prototype.heartSound = function(){
    console.log(this.name+" want rest,but he still "+this.work)
}

var xiaozhang = new Worker("programmer","programmer....");
xiaozhang.heartSound(); // programmer want rest,but he still programmer....

//醫(yī)生也需要休息
var xiaomei = new Worker("doc","sos");
xiaomei.heartSound(); // doc want rest,but he still sos

三李滴、 原型鏈

前面也差不多談到了原型這個概念螃宙,什么叫原型呢?其實我有一個不太好所坯,但是又很恰當(dāng)?shù)睦觼砻枋鲞@些個概念(看嗯哼家小狗谆扎、小貓想到的):

  • 小狗是小狗媽媽生的、小貓是小貓媽媽生的芹助。小狗和小貓被稱為對象的實例堂湖,狗媽媽、貓媽媽被稱為對象的原型
  • 狗媽媽和狗爸爸能通過交配生出一大堆小狗出來状土,其中交配就被稱為構(gòu)造函數(shù)
  • 狗媽媽有很多狗寶寶无蜂,但是狗寶寶卻只有一個狗媽媽,這可以被稱之為原型的唯一性
  • 我們可以通過狗寶寶找到狗媽媽蒙谓,狗媽媽也可以找到狗外婆酱讶,以此類推 這就是相當(dāng)于原型鏈
  • 大家都知道狗有很多品種,很多品種里面也有發(fā)育好的彼乌,發(fā)育差的泻肯、胖的瘦的...例如胖的泰迪也是泰迪=>泰迪也是狗=>狗=>哺乳動物=>動物=>生物∥空眨總之一切的一切都有一個起點灶挟,這條鏈的終點將會被指向同一處,這就好比原型鏈最終指向null
  • 小泰迪生下來之后毒租,它的樣貌會跟泰迪媽媽大同小異稚铣,這就類比于原型的繼承。
  • 小泰迪的主人領(lǐng)養(yǎng)小泰迪之后將其打扮成另外的模樣墅垮,這就類比于對象屬性可以覆蓋原型屬性惕医。但是小泰迪的模樣并不會改變小泰迪弟弟的模樣,這就類比于對象屬性的改變不會影響原型的改變算色。

其實有了上面的一個基本的了解之后抬伺,我們再來一步一步寫代碼就會比較容易了。

{
    function Dog(name){
        this.name = name
    }
    Dog.prototype.action = function(){
        console.log(this.name+" wang..");
    }

    let xiaogou1 = new Dog("xiaogou1");
    xiaogou1.action(); // xiaogou1 wang..

    let xiaogou2 = new Dog("xiaogou2")
    xiaogou2.action(); // xiaogou2 wang..

    let xiaogou3 = new Dog("xiaogou3");
    xiaogou3.action(); // xiaogou3 wang..

}

如上面所示 xiaogou1灾梦、xiaogou2峡钓、xiaogou3被稱為對象實例而Dog被稱為這群小狗的原型∪艉樱可以通過構(gòu)造方法來創(chuàng)建出1能岩,2,3三只小狗萧福。

{
    function Cat(name){
        this.name = name;
    }
    Cat.prototype.action=function(){
        console.log(this.name+" miao!!!")
    }

    function Dog(name){
        this.name = name
    }
    Dog.prototype.action = function(){
        console.log(this.name+" wang..");
    }
    let xiaogou = new Dog("xiaogou");
    xiaogou.action(); // xiaogou wang..

    let xiaomao = new Cat("xiaomao");
    xiaomao.action(); // xiaomao miao!!!
}

上面的代碼中可以瞧出來:小狗能繼承小狗原型上面的action方法去“wang...”,小貓會繼承小貓的原型方法“miao!!!”拉鹃。

{
    function Dog(name){
        this.name = name
    }
    Dog.prototype.action = function(){
        console.log(this.name+" wang..");
    }
    let taidi= new Dog("taidi");
    taidi.action = function(){
        console.log(this.name+ " miao!!!");
    }
    taidi.action() // taidi miao!!!

    let others = new Dog("other dog");
    others.action(); // other dog wang..

}

看上面的代碼可以看出:當(dāng)我們?nèi)娦凶宼aidi的action方法改變的話,我們再進(jìn)行訪問的時候會先訪問到實例上面的屬性“ taidi miao!!!”,但是此時我們再用原型去創(chuàng)造實例的時候膏燕,我們并不會改變新增實例的action方法炭庙,這個說明了實例屬性改變會覆蓋原型屬性,但是不會原型上面的額屬性煌寇。

    delete taidi.action

    taidi.action() // taidi wang..

如上所示焕蹄,當(dāng)我們將泰迪action刪除掉,再訪問action方法則會重新顯示原型上面的方法阀溶。如果我們重復(fù)調(diào)用上面的方法腻脏,卻發(fā)現(xiàn)無法刪除action方法,這進(jìn)一步說明對象屬性不能改變原型的屬性银锻。

四永品、 原型鏈的繼承和徹底了解原型鏈

談到面向?qū)ο竽兀渴紫染蜁氲降氖抢^承击纬。我在這里呢鼎姐?也就來觸類旁通,希望用繼承起手徹底搞清楚這一個東西更振。

{
    //這個是java入門繼承的最好的例子炕桨,拿來講解一哈
    function Animal(name){
        this.name = name
    }
    Animal.prototype.action = function(){
        console.log(this.name+" have running...")
    }
    Animal.prototype.need = function(){
        console.log(this.name+" need breathing")
    }

    function Fish (name){
        Animal.call(this,name)
    }
    Fish.prototype = Object.create(Animal.prototype);
    // Fish.prototype = new Animal() // 如果構(gòu)造函數(shù)有值的時候,這里就不知道該填寫什么了肯腕,就很尷尬
    // Fish.prototype = Animal.prototype; // 如果Fish想重寫父類方法的時候献宫,父類方法也會變化
    Fish.prototype.constructor = Fish;
    Fish.prototype.action = function(){
        console.log(this.name+" have Swimming...")
    }
    let fish = new Fish("fish");
    fish.name = "鯉魚";
    console.log(fish.name) // 鯉魚
    fish.action();
    fish.need();
    fish.best(); // es5:undefined,es6:報錯
    console.log(fish.toString())

}

上面是我手寫的一個js繼承,結(jié)合我下面手繪的一張結(jié)構(gòu)圖來看一下(我找了好多畫圖工具实撒,并沒有發(fā)現(xiàn)好用姊途,希望讀者能推薦一款好用的mac畫圖工具)。

  • 實例魚調(diào)用name屬性知态,發(fā)現(xiàn)原型里面存在捷兰,就會直接輸出。
  • 實例魚在調(diào)用action方法的時候首先會在實例的屬性里面去查找负敏,然后發(fā)現(xiàn)實例的屬性表里面并沒有action屬性贡茅,于是就會向上查找,找到魚的原型原在,然后在父類的原型中找到action就會執(zhí)行其方法友扰。
  • 實例魚在實例屬性中沒有發(fā)現(xiàn)need方法彤叉,于是就會向上查找庶柿。但是發(fā)現(xiàn)Fish的原型中也沒有need方法就會再向上查找,發(fā)現(xiàn)在Animal的實例中發(fā)現(xiàn)有need方法秽浇,于是便執(zhí)行輸出浮庐。
  • 實例魚在實例屬性落竹、Fish原型袜匿、Animal原型上面都沒有發(fā)現(xiàn)toString方法,于是再向上查找,終于在object原型中找到toString方法恶阴,于是便執(zhí)行輸出
  • 實例魚在所有的原型中都沒有找到best方法,而Object的原型向上查找會返回null助泽,于是便執(zhí)行返回undefined熬北。(es6中默認(rèn)開啟嚴(yán)格模式,而在嚴(yán)格模式下面未定義的值會報錯)


    手寫的原型鏈

四璧坟、說在最后

其實這篇文章寫了很久既穆,不知道是因為最近狀態(tài)低迷的緣故 還是時間喚起了我的懶散。我原本是想著上周末的時候就寫完這篇文章雀鹃,然后去專門來搞ts的幻工,結(jié)果上周日自己很蠢的看了兩場世界杯,然后買贏的德國輸了黎茎、買贏的巴西平了囊颅。
誒,盡管身邊一個朋友提醒我:世界杯有人在操盤傅瞻。但是還是不能泯滅我當(dāng)一個偽球迷的熱情踢代。算了,不說了 不說了嗅骄,
日本都贏球了奸鬓,你還有什么理由怨天尤人--致將去洗澡的我

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市掸读,隨后出現(xiàn)的幾起案子串远,更是在濱河造成了極大的恐慌,老刑警劉巖儿惫,帶你破解...
    沈念sama閱讀 212,222評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件澡罚,死亡現(xiàn)場離奇詭異,居然都是意外死亡肾请,警方通過查閱死者的電腦和手機留搔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铛铁,“玉大人隔显,你說我怎么就攤上這事《穑” “怎么了括眠?”我有些...
    開封第一講書人閱讀 157,720評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長倍权。 經(jīng)常有香客問我掷豺,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,568評論 1 284
  • 正文 為了忘掉前任当船,我火速辦了婚禮题画,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘德频。我一直安慰自己苍息,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,696評論 6 386
  • 文/花漫 我一把揭開白布壹置。 她就那樣靜靜地躺著档叔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蒸绩。 梳的紋絲不亂的頭發(fā)上衙四,一...
    開封第一講書人閱讀 49,879評論 1 290
  • 那天,我揣著相機與錄音患亿,去河邊找鬼传蹈。 笑死,一個胖子當(dāng)著我的面吹牛步藕,可吹牛的內(nèi)容都是我干的惦界。 我是一名探鬼主播,決...
    沈念sama閱讀 39,028評論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼咙冗,長吁一口氣:“原來是場噩夢啊……” “哼沾歪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起雾消,我...
    開封第一講書人閱讀 37,773評論 0 268
  • 序言:老撾萬榮一對情侶失蹤灾搏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后立润,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狂窑,經(jīng)...
    沈念sama閱讀 44,220評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,550評論 2 327
  • 正文 我和宋清朗相戀三年桑腮,在試婚紗的時候發(fā)現(xiàn)自己被綠了泉哈。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,697評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡破讨,死狀恐怖丛晦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情提陶,我是刑警寧澤烫沙,帶...
    沈念sama閱讀 34,360評論 4 332
  • 正文 年R本政府宣布,位于F島的核電站搁骑,受9級特大地震影響斧吐,放射性物質(zhì)發(fā)生泄漏又固。R本人自食惡果不足惜仲器,卻給世界環(huán)境...
    茶點故事閱讀 40,002評論 3 315
  • 文/蒙蒙 一煤率、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧乏冀,春花似錦蝶糯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至肢扯,卻和暖如春妒茬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蔚晨。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評論 1 266
  • 我被黑心中介騙來泰國打工乍钻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人铭腕。 一個月前我還...
    沈念sama閱讀 46,433評論 2 360
  • 正文 我出身青樓银择,卻偏偏與公主長得像,于是被迫代替她去往敵國和親累舷。 傳聞我的和親對象是個殘疾皇子浩考,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,587評論 2 350

推薦閱讀更多精彩內(nèi)容