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