之前沒有寫博客的習慣,許多的技術積累都是本身稍微總結一下,不多共享,並不是自私,而是工做比較忙,前幾天接到一個電話面試不理想,才發現公司所用的DOJO並不被外面普遍接受,所學僅爲九牛一毛,故而決定把本身所學分享出來,爲夯實基礎,也爲與外界交流思想,造成一種渠道,如需聯繫,請發送至郵箱:diydyq@126.com。面試
今天寫Javascript系列之第一篇:Prototype原型鏈。在軟件園裏隨便拉一個碼農估計都會寫JS,大部分也知道JS是基於原型的語言,可是若是問及JS原生對象(Object,Function,Array,Date等)的這個原型鏈長什麼樣子?估計能回答出來的人就少了,我開始也很是糊塗,後來決心必定要好好搞一下,花了2天功夫基本算是明白了,分享以下:瀏覽器
測試環境:Firefox、Firebug;
框架
爲作好鋪墊,按順序解釋以下概念:
ide
1)類型、原生類型、對象類型(types、primitive types、object types)
學習
不像咱們在學習JAVA時,被告知JAVA是徹底OOP的語言:class是一類具備共同特色的物體的抽象,object是某個class下具體的一個實現,Object類是全部類的頂層父類,對Java的認知是從類與對象開始的;Javascript則否則,它是從類型(type)開始,在各種語言中遇到的number,string, boolean, object, function,array等都屬於類型。測試
這些類型在JS中分爲兩大類:原生類型與對象類型,原生類型包括:number,string, bool, null, undefined;剩下的非原生類型對象都屬於對象類型,包括:object, array, function等,那這裏的object專指具備屬性(attribute)的對象,在Firebug中的代碼示例以下:this
// 1) primitive types log(typeof 1); // number log(typeof ""); // string log(typeof false); // boolean log(typeof undefined); // undefined log(typeof null); // object null是個特列,屬於原生類型; log(null instanceof Object); // false // 2) object types. log(typeof new Object); // object log(typeof new Function); // function log(typeof new Array); // object log(opts.call(new Object)); // [object Object] log(opts.call(new Function)); // [object Function] log(opts.call(new Array)); // [object Array]
判斷某個值是什麼大的類型沒有意義,每每須要判斷它是什麼原生類型或者對象類型:判斷原生類型,可使用typeof關鍵字;判斷對象類型,可使用toString()方法;
spa
2)prototype與__proto__的區別prototype
二者都是對象類型的屬性,並不是全部的對象類型都有prototype屬性,通常只有function對象纔有prototype屬性(除非主動賦值),它指向的是一個對象,未來會被多個該function的實例所繼承(或者說該對象處於多個實例的原型鏈上);__proto__纔是真正的原型鏈的實際指針,然而許多瀏覽器並不對外公開這個屬性,Firefox暴露出這一屬性,僅供開發人員理解,但不推薦開發中使用。下面咱們用一段代碼來作驗證:指針
// 1) prototype屬性:通常只有function對象擁有 log((new Object).prototype); // undefined log([].prototype); // undefined log((new Function).prototype); // anonymous {} // Function, Object, Array是function對象 log(Function.prototype); // function() log(Object.prototype); // Object {} log(Array.prototype); // [] // 2) __proto__屬性:指向該對象原型鏈的上一端 log((Object.prototype).__proto__); // null log((Function.prototype).__proto__); // Object {} log(Object.__proto__); // function() log(Function.__proto__); // function() // function對象Company的prototype屬性所指的對象處於實例對象的原型鏈上 var Company = function(name){ this.name = name; }; var c1 = new Company("IBM"); var c2 = new Company("Alibaba"); console.log(c1.__proto__ == Company.prototype); // true console.log(c2.__proto__ == Company.prototype); // true
上面的示例咱們確認了__proto__纔是原型鏈中對象之間從下到上的聯繫的橋樑,那麼既然是鏈總該有個頭吧?要是一直找不到頭,就成死鏈了,在JAVA裏全部對象都會繼承來自最頂層父類Object的方法同樣,如:toString方法,JS中會繼承哪些方法呢?
3)原型鏈的最頂端
既然__proto__是鏈的索引,那麼咱們是否能夠辛苦測試一下經常使用的對象呢?
// 原型鏈的頂端 log((Object.prototype).__proto__); // null log(Function.prototype.__proto__ == Object.prototype); // true log(Object.__proto__ == Function.prototype); // true log(Function.__proto__ == Function.prototype); // true log(Array.__proto__ == Function.prototype); // true log(Company.__proto__ == Function.prototype); // true log(Object.__proto__ == Function.prototype); // true log(Company.prototype.__proto__ == Object.prototype); // true log(c1.__proto__ == Company.prototype); // true
通過上面的比較後,咱們基本就能夠畫出這個原型鏈頂端的樣子了, 以下圖:
4)瞭解原型鏈最頂端的意義
意義彷佛應該放在前面講更突出重要性,就當不求甚解吧,我的理解有以下意義:
A) 清楚對象的繼承結構,知道它有哪些父類(父類:指的是該對象原型鏈向上方向的對象);
B) 瞭解並調用父類的方法,不會混淆功能;
C) 多個對象共享原型鏈的某一段時,方便調試;
針對A好處,咱們能夠更好的理解instanceof關鍵字的做用;
針對B好處,咱們能夠調用不一樣父類的方法徹底不一樣的判斷需求,好比:Function.prototype.toString.call(obj)方法用於輸出function對象的定義代碼,Object.prototype.toString.call(obj)方法用於輸出該對象所屬的object類型;
針對C好處,這個便於理解複雜JS框架中對象的內存管理模型,好比:DOJO框架,這個之後會說起。
剛纔咱們用__proto__獲取原型鏈,有沒有一種通用的方式呢?那麼在圖中有個方法能夠作到:
Object.getPrototypeOf(obj),(未測全部瀏覽器,Firefox, IE10能夠)。
關於鏈的樣子就講完了,下期有時間來說Javascript是否能夠模擬OOP;