javascript對象不徹底探索記錄04:小夥子,你對象咋來的?中篇 - 現出你的原型!

舒適提示:做者的爬坑記錄,對你等大神徹底沒有價值,別在我這浪費生命javascript

在上一篇博文javascript對象不徹底探索記錄03:小夥子,你對象咋來的?上篇,中大概說了說在js中,比較好理解的對象建立方式,分別是直接定義/字面量,和調用構造函數java

你對象還有原型?

在一衆博文及書中,有一個高級/很差看明白的方式,比上面這兩種更收到推崇,那就是大名鼎鼎的原型方式,看到這個詞,我表示不是我謙虛,是真懵逼,啥原型,什麼原型,誰的原型?現看看別人給的例子segmentfault

function Car() {
}

Car.prototype.color = "blue";
Car.prototype.doors = 4;
Car.prototype.mpg = 25;
Car.prototype.showColor = function() {
  alert(this.color);
};

var oCar1 = new Car();
var oCar2 = new Car();

源自ECMAScript 定義類或對象 - W3school瀏覽器

別說,還真有那麼點眼熟,這種對象名稱,後面跟一個prototype的寫法,一直以來是我一個重要懵逼來源,話說這詞,不就是原型的意思嗎?函數

prototype
英 [ˈprəʊtətaɪp] 美 [ˈproʊtətaɪp]
n.
原型,雛形,藍本

哈,在這等着我呢,其實認真一看這句Car.prototype.color = "blue";的語法意思是給Carprototypecolor賦值,翻譯一下就是給Car的原型中的color屬性賦值,因此說是否是能理解爲原型也就是prototype是對象的一個屬性呢?仍是從頭瞭解吧this

因此你原型是啥?

提到原型,就不能不提到javascript中的一個重要的懵逼概念 - 原型鏈spa

每一個對象都有一個 私有屬性(稱之爲 [[Prototype]]),它持有一個鏈接到另外一個稱爲其 prototype 對象(原型對象)的 連接。該 prototype 對象又具備一個本身的原型, 層層向上直到一個對象的原型爲 null。(譯者注:Object.getPrototypeOf(Object.prototype) === null; // true)根據定義,null 沒有原型,並做爲這個原型鏈中的最後一個環節。

源自MDN Web docs - Web技術文檔/javascript/繼承與原型鏈prototype

這段話我注意到的有幾個關鍵詞:每一個對象,私有屬性,連接,層層向上翻譯

用直白的話描述一下,在javascript中任何一個對象都有一個叫作原型對象的對象,這個原型對象就是傳說中的prototype,而指向原型對象的連接/指針/箭頭/->/都存在對象內部的一個私有屬性中[[Prototype]]中(*見注1)設計

也就是說對象的[[Prototype]]中並非直接存了原型對象,而是存着一個指向原型對象的連接//這也就使得其是動態的-待研究

由此能夠想到的,既然每一個對象都有原型對象,每一個對象也均可以做爲其餘對象的原型對象,那麼就會造成一個由[[Prototype]]屬性組成的鏈,這就是傳說中的原型鏈了,而利用原型鏈,對象能夠訪問其原型對象的屬性及方法

*注1
[[prototype]]是一個隱藏屬性,但不少瀏覽器都給每個對象提供.__proto__這一屬性,這個屬性就是上文反覆提到的該對象的[[prototype]]。因爲這個屬性不標準,所以通常不提倡使用。ES5中用Object.getPrototypeOf函數得到一個對象的[[prototype]]。ES6中,使用Object.setPrototypeOf能夠直接修改一個對象的[[prototype]]

源自知乎問題 - js中__proto__和prototype的區別和關係? - 知乎用戶的回答

換句話說,任何一個對象,都是在另外一個被叫作原型對象的基礎之上被建立出來的,這也就是所謂的原型了

整這麼麻煩幹嗎?

就像咱們知道的,在學園都市裏有好多少女們/對象,她們各自有不一樣名字,頭髮顏色,以及超能力,她們能夠展示本身的超能力,咱們創建一個名叫GirlFriend()的構造函數,來記錄記錄

function GirlFriend(name,hairColor,power){
    this.name = name;
    this.hairColor = hairColor;
    this.showPower = function(){
        console.log(power)
    }
}

記錄/實例化炮姐和黑子

var mikoto = new GirlFriend("Mikoto","brown","BiliBili");
var kuroko = new GirlFriend("Kuroko","black","Telesport");
mikoto.showPower();//BiliBili
kuroko.showPower();//Telesport

直到這裏一切都很正常,可是卻發現炮姐不是一我的!有人處於某種緣由克隆了好多炮姐,如何記錄炮姐的妹妹們呢,咱們建立一個構造函數Sister()用於記錄炮姐的妹妹們

function Sister(level,number){
    this.level = level;
    this.number = number;
    this.showLevel = function(){
        console.log(this.level);
    }
}

可是妹妹們也是由炮姐克隆而來的啊,炮姐有的屬性她們也都應該有啊,怎麼辦,直接在Sister()裏新增屬性嗎?太麻煩了並且這就跟炮姐不要緊了,炮姐哪天要是在GrilFriend()裏多錄入一個新的屬性,在Sister()也還得繼續添加。
就沒有什麼更好的方式嗎,答案是確定的

因而咱們就用炮姐這個實例對象做爲原型對象

Sister.prototype = mikoto;

在這裏Sister.prototype指的是由構造函數Sister()生成的實例對象所對應的原型對象
說白了,上面這行代碼的的做用就是讓全部由Sister()生成的實例對象的原型對象都是mikoto,咱們來試試結果

var sister = new Sister(3,'0001');
sister.showPower();//BiliBili
sister.showLevel();//3

到此爲止一個擁有3級BiliBili能力的妹妹就誕生了

並且其整個的執行過程也與咱們對的理解同樣,是從內到外,從這兒到那兒的

GirlFriend.prototype.age = 14;
console.log(sister);//見截圖
console.log(sister.age)//14

運行結果
從結果中能夠看出,sister對象內部並無age屬性,在sister對象的原型對象mikoto中也沒有age屬性,可是在mikoto的原型對象中包含age屬性而且有值,因此sister對象就順着原型鏈一路找到了第一個age屬性

但其實sister的由於是被克隆出來的因此只有1歲而已

sister.age = 1;
console.log(sister);//見截圖
console.log(sister.age)//1

運行結果
從運行結果能夠看出,sister對象內部有age屬性,這個是sister原型鏈上第一個age屬性,因此sister.age的值就取1
爲由GirlFriend()實例化對象的原型對象增長屬性age並賦值,看看sister.age

能在說細點嗎

在上文代碼和截圖中出現了兩個和prototype相關的詞,prototype和_proto_,這倆貨是幹啥的?
其實上文提到了,構造函數Foo()的prototype屬性指的就是這個構造函數所對應的原型對象,其實就是經過Foo()建立的對象的原型對象,因此prototype是構造函數所具備的一個屬性
而_proto_屬性是對應對象所說的,見上文注1所說,舉個例子

sister.__proto__.age = 1
console.log(mikoto.age);//1
console.log(kuroko.age);//14
sister.__proto__.__proto__.age = 1
console.log(kuroko.age);//1

正如例子中表現的,對象能夠經過_proto_屬性得到本身的原型對象,以及原型鏈上每個對象

在截圖中的原型對象中,還存在一個constructor的屬性,這個屬性指向的就是這個原型對象所對應的構造函數,也就是那個構造出原型對象爲該對象的函數,一句話歸納就是構造函數和其對應的對象互相擁有彼此,構造函數將對象放在prototype屬性中,對象將構造函數放在constructor屬性中我想這就是愛情吧

這裏再放一張圖,就能更清除解釋他們之間的關係了
prototype,_proto_,construtor之間關係

源自知乎問題 - js中__proto__和prototype的區別和關係? - doris的回答

話說回來

繞了這麼大一圈,還沒忘咱們爲何要研究原型吧,經過原型的方式建立對象的屬性和方法,就能夠利用同種對象類型的不一樣實例擁有想用的原型對象這一特性,避免重複建立,而且在修改原型對象的某個屬性後,也能夠經過原型鏈影響到其餘全部相關對象上。

舉個例子

GirlFriend.prototype.sayHello = function(){
    console.log("Ohayo!")
}
kuroko.sayHello();//Ohayo!
sister.sayHello();//Ohayo!

而且說到底她們執行的都是同一個sayHello()

關於原型這塊概念相對複雜,還設計嵌套,相互引用等等深坑,仍是得先捋清楚再本身多作聯繫來理解和熟練運用啦
能看到這的估計都懵逼了

相關文章
相關標籤/搜索