JS-理解原型與原型鏈

構(gòu)造函數(shù)

構(gòu)造函數(shù)就是一個普通的函數(shù),創(chuàng)建方式和普通函數(shù)沒有區(qū)別枯饿,不同的是構(gòu)造函數(shù)習慣上首字母大寫。另外就是調(diào)用方式的不同诡必,普通函數(shù)是直接調(diào)用奢方,而構(gòu)造函數(shù)需要使用new關(guān)鍵字來調(diào)用

    function Person(name, age, gender) {
        this.name = name
        this.age = age
        this.gender = gender
        this.sayName = function () {
            alert(this.name);
        }
    }
    var per = new Person("孫悟空", 18, "男");
    function Dog(name, age, gender) {
        this.name = name
        this.age = age
        this.gender = gender
    }
    var dog = new Dog("旺財", 4, "雄")
    console.log(per);//當我們直接在頁面中打印一個對象時,事件上是輸出的對象的toString()方法的返回值
    console.log(dog);

每創(chuàng)建一個Person構(gòu)造函數(shù)蟋字,在Person構(gòu)造函數(shù)中稿蹲,為每一個對象都添加了一個sayName方法,也就是說構(gòu)造函數(shù)每執(zhí)行一次就會創(chuàng)建一個新的sayName方法鹊奖。這樣就導致了構(gòu)造函數(shù)執(zhí)行一次就會創(chuàng)建一個新的方法苛聘,執(zhí)行10000次就會創(chuàng)建10000個新的方法,而10000個方法都是一摸一樣的忠聚,為什么不把這個方法單獨放到一個地方设哗,并讓所有的實例都可以訪問到呢?這就需要原型(prototype)


原型

在JavaScript中,每當定義一個函數(shù)數(shù)據(jù)類型 (普通函數(shù)咒林、類)時候熬拒,都會天生自帶一個prototype屬性,這個屬性指向函數(shù)的原型對象垫竞,并且這個屬性是一個對象數(shù)據(jù)類型的值澎粟。
image.png

原型對象就相當于一個公共的區(qū)域,所有同一個類的實例都可以訪問到這個原型對象欢瞪,我們可以將對象中共有的內(nèi)容活烙,統(tǒng)一設(shè)置到原型對象中。

 function Person(name,age){
            this.name=name
            this.age=age
            this.sayName = function () {
                alert(this.name);
            }
        }

改造下

 function Person(name,age){
            this.name=name
            this.age=age
        }
 
        Person.prototype.year=2021   // 往原型上添加一點東西
        Person.prototype.sayName =function(){
            alert(this.name);
        }
        const personA=new Person()
        const personB=new Person()
        console.log('personA',personA , personB)
        console.log(personA.hasOwnProperty('year'), 'year' in personA ) // false true
        console.log(personB.hasOwnProperty('year'), 'year' in personB) // false true
        // hasOwnProperty只會從實例本身上找屬性遣鼓, in會從實例所屬類的原型身上找
        console.log('personA.year',personA.year , personB.year )  // 2021 2021

原型的作用:
1:實現(xiàn)對象之間的數(shù)據(jù)共享啸盏。
2.在es6之前,沒有class的情況下骑祟,模擬面向?qū)ο蠡嘏常瑯?gòu)造函數(shù)中放私有屬性,原型上放公有屬性次企,一般放方法怯晕。

通過原型添加的方法,可以完美的解決屬性與方法共享問題,從而節(jié)省了內(nèi)存空間..


原型鏈

每一個對象數(shù)據(jù)類型(普通的對象、實例缸棵、prototype......)也天生自帶一個屬性__proto__舟茶,這個屬性的值是當前實例所屬類的原型對象(prototype)。
原型對象中有一個屬性constructor, 它指向構(gòu)造函數(shù)堵第。

image.png
    function Person() {}   // 構(gòu)造函數(shù)
    var person = new Person()  // 實例person
    console.log(person.__proto__ === Person.prototype)  // true
    console.log(Person.prototype.constructor===Person)  // true

    //順便學習一個ES5的方法,可以獲得對象的原型
    console.log(Object.getPrototypeOf(person) === Person.prototype)   // true

js實例對象的原型屬性__proto__的屬性值吧凉,指向這個實例對象所屬類的原型

例如 new Array 出來的數(shù)組,屬于Array這個類

const xArray=new Array()

那么

xArray.__proto__ === Array.prototype  // true

Array.prototype擁有的方法踏志,array的每一個實例都會有阀捅,直接通過xArray.push()這樣調(diào)用,而不需要xArray._ proto _.push针余,不需要這樣去調(diào)用也搓。

 Array.prototype.__proto__ === Object.prototype  // true
Object.prototype._proto_  // null

所謂原型鏈赏廓,指的就是這一條指針鏈!

原型鏈的頂層就是Object.prototype傍妒,而Object的原型對象的是沒有原型屬性的幔摸。 Object.prototype._proto_ ===null


何為原型鏈

在JavaScript中萬物都是對象,對象和對象之間也有關(guān)系颤练,并不是孤立存在的既忆。對象之間的繼承關(guān)系,在JavaScript中是通過prototype對象指向父類對象嗦玖,直到指向Object對象為止患雇,這樣就形成了一個原型指向的鏈條,專業(yè)術(shù)語稱之為原型鏈宇挫。

舉例說明:person → Person → Object 苛吱,普通人繼承人類,人類繼承對象類

當我們訪問對象的一個屬性或方法時器瘪,它會先在對象自身中尋找翠储,如果有則直接使用,如果沒有則會去原型對象中尋找橡疼,如果找到則直接使用援所。如果沒有則去原型的原型中尋找,直到找到Object對象的原型,Object對象的原型沒有原型欣除,如果在Object原型中依然沒有找到住拭,則返回undefined。

我們可以使用對象的hasOwnProperty()來檢查對象自身中是否含有該屬性历帚;使用in檢查對象中是否含有某個屬性時滔岳,如果對象中沒有但是原型中有,也會返回true

function Person() {}
    Person.prototype.a = 123;
    Person.prototype.sayHello = function () {
      alert("hello");
 };
    var person = new Person()
    console.log(person.a)//123
    console.log(person.hasOwnProperty('a'));//false
    console.log('a'in person)//true

person實例中沒有a這個屬性挽牢,從 person 對象中找不到 a 屬性就會從 person 的原型也就是 person.__proto__澈蟆,也就是 Person.prototype中查找,很幸運地得到a的值為123卓研。那假如 person.__proto__中也沒有該屬性,又該如何查找睹簇?

當讀取實例的屬性時奏赘,如果找不到,就會查找與對象關(guān)聯(lián)的原型中的屬性太惠,如果還查不到磨淌,就去找原型的原型,一直找到最頂層Object為止凿渊。Object是JS中所有對象數(shù)據(jù)類型的基類(最頂層的類)梁只,在Object.prototype上沒有__proto__這個屬性缚柳。

console.log(Object.prototype.__proto__ === null) // true
image.png

所謂原型鏈,指的就是圖中的proto這一條指針鏈搪锣!

原型鏈的頂層就是Object.prototype秋忙,而Object的原型對象的是沒有原型屬性的。

先找自身构舟,找不到就沿著__proto__一直往上找原型灰追,直到找到最頂層的類Object,Object類沒有原型了狗超,如果還找不到就返回undefined



實戰(zhàn):用ES6的class定義一套對象/函數(shù)

ES6提供了class弹澎,但是這個并不是類,而是 Function 的語法糖努咐。
目的是簡化ES5里面苦蒿,為了實現(xiàn)繼承而采用的各種“神操作”。

用class來定義渗稍,結(jié)構(gòu)和關(guān)系會非常清晰佩迟,再也不會看著頭疼了,建議新手可以跳過ES5的實現(xiàn)方式免胃,直接用ES6的方式音五。

我們先定義一個Base,然后定義一個Person繼承Base羔沙,再定義一個Man繼承Person躺涝。
也就是說,可以深層繼承扼雏。

class Base {
  constructor (title) {
    this.title = '測試一下基類:' + title
  }

  baseFun1(info) {
    console.log('\n這是base的函數(shù)一坚嗜,參數(shù):', info, '\nthis:', this)
  }
}

class Person extends Base{
  constructor (title, age) {
    super(title)
    this.title = '人類:' + title
    this.age = age
  }

  personFun1(info) {
    console.log('\n這是base的函數(shù)一,參數(shù):', info, '\nthis:', this)
  }
}


class Man extends Person {
  constructor (title, age, date) {
    super(title, age)
    this.title = '男人:' + title
    this.birthday = date
  }

  manFun3 (msg) {
    console.log('jim 的 this ===', this, msg)
  }
}

  • 構(gòu)造函數(shù) constructor
    打印結(jié)果很清晰的表達了诗充,構(gòu)造函數(shù)就是我們定義的class苍蔬。

  • 屬性
    屬性比較簡單,統(tǒng)統(tǒng)都掛在 this 上面蝴蜓,而且是同一個級別碟绑。

  • 函數(shù)
    函數(shù)就有點復雜了,首先函數(shù)是分級別的茎匠,掛在每一級的原型上面

  • 原型鏈
    Man的實例 > Man的原型 > Person的原型 > Base 的原型 > Object 的原型格仲。
    通過 __proto__ 連接了起來。

    image.png

Man的實例 man1诵冒,可以通過這個“鏈條”凯肋,找到 baseFun1,
直接用 man1.baseFun1() 即可(?)汽馋,
而不需要使用__proto__ 侮东;
man1.__ proto__.__ proto__.__ proto__.baseFun1() (?)

man1.__ proto__ === Man.prototype
Man.prototype .__proto__ === Person.prototype
Person.prototype .__proto__ === Base.prototype
Base.prototype .__proto__ === Object.prototype
Object.prototype .__proto__ === null

image.png

Object是js頂層類圈盔,原型鏈的頂端也就是Object.prototype ,Object.prototype沒有__proto__屬性




最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市悄雅,隨后出現(xiàn)的幾起案子驱敲,更是在濱河造成了極大的恐慌,老刑警劉巖煤伟,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件癌佩,死亡現(xiàn)場離奇詭異,居然都是意外死亡便锨,警方通過查閱死者的電腦和手機围辙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來放案,“玉大人姚建,你說我怎么就攤上這事≈ㄑ常” “怎么了掸冤?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長友雳。 經(jīng)常有香客問我稿湿,道長,這世上最難降的妖魔是什么押赊? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任饺藤,我火速辦了婚禮,結(jié)果婚禮上流礁,老公的妹妹穿的比我還像新娘涕俗。我一直安慰自己,他們只是感情好神帅,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布再姑。 她就那樣靜靜地躺著,像睡著了一般找御。 火紅的嫁衣襯著肌膚如雪元镀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天霎桅,我揣著相機與錄音栖疑,去河邊找鬼。 笑死哆档,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的住闯。 我是一名探鬼主播瓜浸,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼澳淑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了插佛?” 一聲冷哼從身側(cè)響起杠巡,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎雇寇,沒想到半個月后氢拥,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡锨侯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年嫩海,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片囚痴。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡叁怪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出深滚,到底是詐尸還是另有隱情奕谭,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布痴荐,位于F島的核電站血柳,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏生兆。R本人自食惡果不足惜难捌,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望皂贩。 院中可真熱鬧栖榨,春花似錦、人聲如沸明刷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辈末。三九已至愚争,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間挤聘,已是汗流浹背轰枝。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留组去,地道東北人鞍陨。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親诚撵。 傳聞我的和親對象是個殘疾皇子缭裆,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

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