摘要:先來看一個(gè)這樣的對(duì)象在函數(shù)的原型上擴(kuò)展了一個(gè)方法可以看到實(shí)例化的對(duì)象下有一個(gè)屬性,而這個(gè)屬性就指向構(gòu)造函數(shù)的原型對(duì)象。重點(diǎn)是,連接的是實(shí)例對(duì)象與構(gòu)造函數(shù)原型對(duì)象,而不是,實(shí)例對(duì)象和構(gòu)造函數(shù)。
前言
介紹原型的概念,和相關(guān)屬性,以及jquery判斷純凈對(duì)象的實(shí)現(xiàn),不小心點(diǎn)進(jìn)來的直接 ctrl+f 搜你想找的屬性。
什么是原型
isPrototypeOf() || Object.getPrototypeOf()
hasOwnProperty() || in
jQuery.isPlainObject() 源碼解讀
什么是原型prototype(原型,雛形,藍(lán)本) 說新上市的一部手機(jī)的原型機(jī),就可以用這個(gè)單詞。
每一個(gè)函數(shù)默認(rèn)都有一個(gè)prototype(原型)屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象。就是說函數(shù)的原型是一個(gè)對(duì)象。先來打印一個(gè)函數(shù)的這個(gè)prototype屬性,來看看他是什么樣的。
function Zoom(){}; var proto = Zoom.prototype; console.log(proto);
眼見為實(shí),這就是Zoom函數(shù)的原型對(duì)象,其中還有一個(gè)constructor 屬性,我們并未對(duì)prototype原型對(duì)象進(jìn)行修改,但卻有一個(gè)constructor屬性。默認(rèn)情況下,函數(shù)的原型對(duì)象都會(huì)獲取到一個(gè)constructor屬性。
constructor(構(gòu)造器)英文中的解釋為構(gòu)造器。圖中constructor的屬性值為Zoom函數(shù)。便于記憶,也可以理解為,函數(shù)的原型是由函數(shù)產(chǎn)生的,那構(gòu)造出原型的東西,就是函數(shù)本身。也就是:
Zoom.prototype.constructor = Zoom; //語言描述就是:zoom函數(shù)的原型對(duì)象的constructor屬性,指向函數(shù)本身。
當(dāng)我們通過new操作符,獲取了一個(gè)構(gòu)造函數(shù)的實(shí)例后(就是產(chǎn)生了一個(gè)對(duì)象)。先來看一個(gè)這樣的對(duì)象:
function Zoom(){ this.bird = function(){ console.log("bird"); } }; //在函數(shù)的原型上擴(kuò)展了一個(gè)方法 Zoom.prototype.cat = function(){ console.log("cat"); } var zoom = new Zoom(); console.log(zoom);
可以看到實(shí)例化的zoom對(duì)象下有一個(gè)__proto__屬性,而這個(gè)屬性就指向構(gòu)造函數(shù)Zoom的原型對(duì)象。重點(diǎn)是,__proto__連接的是實(shí)例對(duì)象與構(gòu)造函數(shù)原型對(duì)象,而不是,實(shí)例對(duì)象和構(gòu)造函數(shù)。
isPrototypeOf() || getPrototypeOf()function Zoom(){ this.bird = function(){ console.log("bird"); } }; //在函數(shù)的原型上擴(kuò)展了一個(gè)方法 Zoom.prototype.cat = function(){ console.log("cat"); } Zoom.prototype.fish= function(){ console.log("fish"); } var zoom1 = new Zoom(); var zoom2 = new Zoom(); zoom1.cat ();//cat zoom2.fish();//fish console.log(zoom1); console.log(zoom2);
根據(jù)上一節(jié)說的,zoom1,zoom2實(shí)例對(duì)象都有一個(gè)屬性__proto__指向構(gòu)造函數(shù)的原型對(duì)象,換句話說,就是實(shí)例對(duì)象和構(gòu)造函數(shù)沒什么直接的聯(lián)系。
但是我們發(fā)現(xiàn),這兩個(gè)實(shí)例都不包含方法,卻能夠使用a,b 方法,這就是通過查找對(duì)象屬性的過程來實(shí)現(xiàn)的。
當(dāng)我們?cè)谡{(diào)用一個(gè)對(duì)象的屬性值是,首先會(huì)從實(shí)例對(duì)象本身開始搜索,如果找到了就返回屬性值,沒有找到就在原型對(duì)象上查找。這也是原型對(duì)象的屬性或方法可以共享的原因。
那如何知道一個(gè)對(duì)象,例如兩個(gè)實(shí)例的原型鏈中,是否有構(gòu)造函數(shù)的原型對(duì)象(Zoom)的方法呢。這就是isPrototypeOf()。用來確定一個(gè)對(duì)象是否存在于另一個(gè)對(duì)象的原型鏈中。
console.log(Zoom.prototype.isPrototypeOf(zoom1));//true
雖然原型可以共享,但是不能通過實(shí)例對(duì)象修改原型:
zom1.cat = function (){ console.log("zom1 輸出的 cat"); } zom1.cat ();//z1 輸出的 cat zom2.cat ();//原型輸出的cat
這個(gè)其實(shí)很好理解,因?yàn)閷?duì)象屬性查找是從實(shí)例向原型上查找,所以寫在實(shí)例上的方法如果和原型上的方法同名的話,會(huì)屏蔽原型上的方法,可以簡單理解為就近原則。
hasOwnProperty() || in既然同一個(gè)方法可以出現(xiàn)在實(shí)例中,也可以出現(xiàn)在原型中,如何可以判斷是否在實(shí)例中呢。
hasOwnProperty() 方法會(huì)返回一個(gè)布爾值,指示對(duì)象是否具有指定的屬性作為自身(不繼承)屬性。
如果判斷在zoom1對(duì)象自身是否有a屬性,就可以:
zoom1.hasOwnProperty(bird); // true zoom1.hasOwnProperty(fish); // false
因?yàn)閎ird 是zoom1 自身的屬性,所以返回true,而fish是zoom1原型的的屬性,所以返回false。
另一個(gè)要介紹的in方法,它比hasOwnProperty判斷的范圍更大,無論在原型上或者是在實(shí)例上,如果存在要檢測的屬性,都會(huì)返回true。
"bird" in zoom1; // true "fish" in zoom1; // false
那就可以理解為,在in方法的判斷范圍中中排除hasOwnProperty的判斷范圍,剩下的不就是屬性只出現(xiàn)在原型中的可能。
轉(zhuǎn)為簡單邏輯就是,如果in為真則可能在實(shí)例中也可能在原型中,如果hasOwnProperty方法為假,就肯定不是在實(shí)例中。所以in為真,hasOwnProperty為假,就一定是在原型中:
function hasProtoTypeProto(attr,obj){ return !obj.hasOwnProperty(attr) && (attr in obj) } hasProtoTypeProto("fish",zoom1) //true hasProtoTypeProto("bird",zoom1) //falseisPlainObject()
是jquery提供的外部可以直接使用的方法,這個(gè)方法是用來判斷一個(gè)對(duì)象是否是純粹的對(duì)象,即對(duì)象字面量,而不是一個(gè)構(gòu)造函數(shù)的實(shí)例。其中涵蓋了大部分原型相關(guān)的方法。我們先來看一下如何使用。
var log = console.log.bind(console); log(jQuery.isPlainObject({x:0}));//true log(jQuery.isPlainObject(new Object({})))//true log(jQuery.isPlainObject([0]))//false function Zoom(){ this.fish = function(){ return "Im a fish"; } } var zoom = new Zoom(); log(jQuery.isPlainObject(zoom))//false
可以看到只有純粹的對(duì)象才會(huì)返回真,typeof類型檢測出數(shù)組為object,或是構(gòu)造函數(shù)的實(shí)例都是返回假。我們看一看在jquery 3.1版本中是如何實(shí)現(xiàn)這個(gè)方法的。分析過程請(qǐng)見代碼:
//傳入需要判斷的對(duì)象 function isPlainObject(obj) { //沒有具體的意義只是保存其他執(zhí)行的結(jié)果。 var proto, Ctor; if (!obj || toString.call(obj) !== "[object Object]") { // toString 在之前的代碼中已被定義為 Object.prototype.toString,代碼等價(jià)于Object.prototype.toString.call( obj ) !== "[object Object]" //在任何值上調(diào)用Object 原生的toString()方法,都會(huì)返回一個(gè)[object NativeConstructorName] 格式的字符串, //[[Class]]是一個(gè)內(nèi)部屬性,所有的對(duì)象(原生對(duì)象和宿主對(duì)象)都擁有該屬性,這個(gè)屬性中就指定了上述字符串中的構(gòu)造函數(shù)名(NativeConstructorName) // 類似的 [object Array] [object Function] [object RegExp] //但是這個(gè)判斷不能排除一個(gè)實(shí)例對(duì)象,因?yàn)樯蟍[Class]] 屬性默認(rèn)保存對(duì)象的類型,所以也會(huì)返回Object; //所以除了對(duì)象的其他類型,都會(huì)返回false return false; } proto = getProto(obj); // getProto 之前已經(jīng)被定義為 getProto = Object.getPrototypeOf 返回對(duì)象構(gòu)造函數(shù)的原型 // Objects with no prototype (e.g., `Object.create( null )`) are plain // 上一行是坐著的注釋,即為通過Object.create( null ) 方法,可以創(chuàng)建一個(gè)沒有原型的對(duì)象null // 所以如果proto 為false,表示對(duì)象沒有原型,只會(huì)是null,而null也是一個(gè)純粹的對(duì)象,所以返回真 if (!proto) { return true; } Ctor = hasOwn.call(proto, "constructor") && proto.constructor; // Objects with prototype are plain iff they were constructed by a global Object function // hasOwn之前被定義為,hasOwn = {}.hasOwnProperty // hasOwn.call( proto, "constructor" ) 傳入對(duì)象構(gòu)造函數(shù)的原型,判斷原型上面有沒有constructor屬性(而不是在原型鏈的其他位置),因?yàn)閏onstructor屬性只會(huì)出現(xiàn)在Object函數(shù)的原型上,其他函數(shù)原型的constructor屬性,都是從Object原型上繼承來的 // 所以有constructor屬性表示是通過Object對(duì)象得到的,但是還不能確定為是Object的實(shí)例,或是字面量方式得到。最后保存proto.constructor 即是傳入對(duì)象的構(gòu)造函數(shù) return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString; // fnToString被定義為hasOwn.toString 即是{}.hasOwnProperty.toString.call(Ctor); // ObjectFunctionString定義為fnToString.call( Object ) 即是{}.hasOwnProperty.toString.call(Object); // 所以 typeof Ctor = "fuction" 為函數(shù)就是需要判斷對(duì)象的原型是函數(shù)類型,{}.hasOwnProperty目的是得到一個(gè)函數(shù),一個(gè)函數(shù)的toString方法會(huì)以字符串的格式顯示函數(shù) // 如果兩個(gè)字符串相等,表示兩個(gè)函數(shù)相等。也就表示傳入對(duì)象的構(gòu)造函數(shù)就是Object,所以他是一個(gè)純凈的對(duì)象。 }
至此就是全文的所有內(nèi)容,有疑問盡情留言,一定回復(fù)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/85221.html
摘要:原型數(shù)據(jù)類型檢測指向綁定執(zhí)行環(huán)境深拷貝三源碼分析匿名自執(zhí)行函數(shù)和閉合包這里形成閉包保護(hù)變量不被直接訪問和篡改保證框架完整性,閉包的作用域內(nèi)也會(huì)幫助緩存變量值。 一、導(dǎo)讀 文章作為學(xué)習(xí)筆記的形式,記錄學(xué)習(xí)的一點(diǎn)體會(huì)和原理知識(shí),如有錯(cuò)誤歡迎指正。 本文根據(jù)一些簡單的jQuery源碼入手分析一個(gè)框架從哪方面入手,js在底層做了那些事, 了解他的設(shè)計(jì)思想,jquery整體架構(gòu)還是依托于js,在...
摘要:通常的做法是,為它們指定回調(diào)函數(shù)。請(qǐng)求返回請(qǐng)求返回請(qǐng)求返回異步隊(duì)列解耦異步任務(wù)和回調(diào)函數(shù)為模塊隊(duì)列模塊事件提供基礎(chǔ)功能。 前言 jQuery整體框架甚是復(fù)雜,也不易讀懂,這幾日一直在研究這個(gè)笨重而強(qiáng)大的框架。jQuery的總體架構(gòu)可以分為:入口模塊、底層模塊和功能模塊。這里,我們以jquery-1.7.1為例進(jìn)行分析。 jquery的總體架構(gòu) 16 (function( window,...
摘要:介一回,偶們來聊一下用中的類,有些盆友可能用過或者的,知道語法糖,可是在中并沒有,中需要用到構(gòu)造函數(shù)來模擬類。而且要注意一點(diǎn),構(gòu)造函數(shù)沒有語句,是自動(dòng)返回。 本回內(nèi)容介紹 上一回聊到JS的Function類型,做了柯里化,數(shù)組去重,排序的題。 介一回,偶們來聊一下用JS中的類,有些盆友可能用過ES6或者TypeScript的,知道Class語法糖,可是在ES5中并沒有,ES5中需要用到...
摘要:說明中的函數(shù)用于判斷指定參數(shù)是否是一個(gè)純粹的對(duì)象,返回值為類型。使用語法參數(shù)說明任意類型需要進(jìn)行判斷的任意值。函數(shù)的方法會(huì)返回一個(gè)表示函數(shù)源代碼的字符串。具體來說,包括關(guān)鍵字,形參列表,大括號(hào),以及函數(shù)體中的內(nèi)容。 說明 jQuery中的isPlainObject() 函數(shù)用于判斷指定參數(shù)是否是一個(gè)純粹的對(duì)象,返回值為Boolean類型。 純粹的對(duì)象,就是通過 { }、new Obje...
摘要:此模塊包含的設(shè)計(jì)思路即為預(yù)以匹配降級(jí)方案。沒有默認(rèn)編譯該模塊,以及利用該模塊判斷后提供平臺(tái)相關(guān)邏輯的主要原因在于其設(shè)計(jì)原則的代碼完成核心的功能。此處,也引出了代碼實(shí)現(xiàn)的另一個(gè)基本原則面向功能標(biāo)準(zhǔn),先功能覆蓋再優(yōu)雅降級(jí)。 在進(jìn)入 Zepto Core 模塊代碼之前,本節(jié)簡略列舉 Zepto 及其他開源庫中一些 Polyfill 的設(shè)計(jì)思路與實(shí)現(xiàn)技巧。 涉及模塊:IE/IOS 3/Dete...
閱讀 2422·2019-08-29 13:53
閱讀 2506·2019-08-29 11:32
閱讀 3046·2019-08-28 17:51
閱讀 3775·2019-08-26 10:45
閱讀 3490·2019-08-23 17:51
閱讀 2982·2019-08-23 16:56
閱讀 3335·2019-08-23 16:25
閱讀 3085·2019-08-23 14:15