1. 程式人生 > >你不知道的js型別轉化和原型鏈

你不知道的js型別轉化和原型鏈

昨天晚上接到了螞蟻金服的電面。其中有一道題,讓我印象深刻,結束之後,我就去查了資料,寫了一篇拙劣的文章來總結。

問題

var a = {}; a.__proto__ === ?
var a = 1; a.__proto__ === ?

當時模稜兩可,我知道他們的頂端都是Object.prototype就直接回答這個選項,因為當時心裡想著一切不是皆物件嗎,那物件的原型鏈頂端不就是Object.prototype嗎?還有為什麼數字有原型鏈?腦子浮現出Functin,Array各種資料型別,但是還是非常的模糊,回答了之後面試官也沒有繼續追問(可能覺得我不清楚吧),但是這個問題始終是我心裡的一個結,查了一些資料後,並對其進行了整理。

大家都知道,JavaScript的資料型別分為兩種,一種是基礎資料型別,另一種是引用資料型別。

什麼是基礎型別(primitive)?

[Aprimitive(primitive value, primitive data type) is data that is not an object and has no methods.]沒有屬性和方法的資料。

型別轉化

首先我們看第二個問題,從第二個問題著手來講解,var a = 1; a.__proto__=== ? 去瀏覽器執行下可以知道,a.__proto__=== Number.prototype, 然後我們再這樣執行 a.__proto__.__proto__=== Object.prototype得到的結果竟然是true。

在前端我們說了,js分兩種型別,那為什麼一個數字(a)的原型鏈頂端是Object的原型?兩者是怎麼聯絡的?primitive 不是沒有屬性和方法嗎?哪裡來的原型鏈?

原來是這樣的,js是弱語言,如果他發現型別不匹配的時候,他會幹嘛?他會型別轉化(Auto Convert)啊。

所以以上的問題變形一下就變成了var a = 1; new Number(a).__proto__=== ?這樣問題就變得很明瞭了,一個Number方法,構造了一個Number的例項,那麼原型鏈肯定是Number的原型啊(即Number.prototype)。再者,一個Number方法構造出的例項,必然有原型鏈。既然已經是一個例項,就是一個物件,再往上,必然是Object.prtotype。

再看一下栗子。

var a = "abc"; console.info(a.length); var b = 1; console.info(b.toString());

這就是我們平常一直在使用的,理解上面的問題,你心中肯定知道了原因,為什麼a,b是primitive,但是為什麼還有其他的屬性。也是因為型別的轉化,等同於

var a = "abc"; console.info(new String(a).length); var b = 1; console.info(new Number(b).toString());

小結

總結以上,所以,js基礎型別確實和引用型別沒有關係!沒有關係!讓他們發生關係的是!型別轉化。(因為js自身原因,強行讓他們發生了關係)。並且基礎型別沒有方法,沒有屬性。

所以我覺得那句,js萬物皆物件,真的有點坑人。

原型鏈

但是後來我又想,不是還有一些function,array,date之類的嗎,那些又是什麼,屬於什麼。這次我一併將他們理清楚。還有那些強行發生關係的建構函式,例如Number,String,Boolean,Date?

以上就是我整理的關係以及引用型別的原型鏈走向。

提示(有些不太明白同學可能會誤會):

(我把Date,Number,Boolean,String歸類到了Function。而剛才不是說原型鏈上是Objec.prototype麼,那是你要搞清楚方法和new 方法(),方法通過new物件就變成了Object。下面也進行一些證明)

小結

Object只是在js中充當了一個複雜的型別,包含了許多的子集,但是Object和基礎型別還是屬於平行關係了。

延伸

通過以上的理解,還自己建立了一個用原型鏈對型別判斷的方法。(因為據說用Object.prototype.toString.call()這樣的實現方式有點醜陋而且奇怪的方法,別人會不明白你寫的是什麼東西。)

var a = null; var b = 1; var c = '1'; var d = undefined; 
var g = true; var e = function (){}; var f = []; 
var h = new Date(); var i = {} function type(a) { if(a === null) { return 'null'; 
} if(typeof a === 'number') { return 'number'; 
} if(typeof a === 'string') { return 'string' } if(typeof a === 'undefined') { return 'undefined'; 
} if(typeof a === 'boolean') { return 'boolean'; } if(a instanceof Array) { return 'array'; 
} if(a instanceof Date) { return 'date'; } if(a instanceof Function) { return 'function'; 
} if(a instanceof Object) { return 'object'; } } console.log(type(a)); 
// null console.log(type(b)); // number console.log(type(c)); 
// string console.log(type(d)); // undefined console.log(type(f)); 
// array console.log(type(e)); // function console.log(type(g)); // boolean console.log(type(h)); 
// date console.log(type(i)); // object

總結

通過以上無非就想說明基礎型別和引用型別的關係,以及各個型別的原型鏈。說的有點亂,如果有不對的地方請提出,我及時更正,以免帶來誤導。 留下一個問題,如果以上說的你都理解了,那麼你必然知道這個答案。

var a = 1; a.a = 1; console.log(a.a);

“小編每晚都會講解企業案例知識點,也有準備一份適合2018年學習的web前端教程,html+css+原生js到H5移動端及各種框架都有整理,送給每一位前端小夥伴,這裡是暴走前端院,歡迎初學和進階中的小夥伴。”

想要學習或者瞭解web前端程式設計的小夥伴,可以加群:575308719(學習交流/領取教程)