實現extend 所須要的功能性函數html
// 判斷是否是函數 function isFunction(obj) { // Support: Chrome <=57, Firefox <=52 /* 在有些瀏覽器 typeof document.createElement( "object" ) 會返回function 因此判斷是否是dom 節點 */ return typeof obj === "function" && typeof obj.nodeType !== "number"; }; // 建立一個計劃對象 let class2type = {}; // 代理 hasOwnProperty 訪問Object.hasOwnProperty的時候能夠節省代碼 let hasOwn = class2type.hasOwnProperty; // hasOwn toString方法 注意是函數的toString方法,而不是{}toString 方法 let fnToString = hasOwn.toString; // Object() 函數轉成字符串 "function Object() { [native code] }" let ObjectFunctionString = fnToString.call(Object); // 代理 let getProto = Object.getPrototypeOf; // 拷貝計劃對象方法 toString = class2type.toString; // 判斷是否爲計劃對象 /* //在當前頁面內追加換行標籤和指定的HTML內容 function w( html ){ document.body.innerHTML += "<br/>" + html; } w( $.isPlainObject( { } ) ); // true w( $.isPlainObject( new Object() ) ); // true w( $.isPlainObject( { name: "CodePlayer"} ) ); // true w( $.isPlainObject( { sayHi: function(){} } ) ); // true w( $.isPlainObject( "CodePlayer" ) ); // false w( $.isPlainObject( true ) ); // false w( $.isPlainObject( 12 ) ); // false w( $.isPlainObject( [ ] ) ); // false w( $.isPlainObject( function(){ } ) ); // false w( $.isPlainObject( document.location ) ); // false(在IE中返回true) function Person(){ this.name = "張三"; } w( $.isPlainObject( new Person() ) ); // false window false new Date false */ function isPlainObject(obj) { var proto, Ctor; // obj false,或者obj不是對象,排除null和undefined 不然getProto(obj) 報錯 if (!obj || toString.call(obj) !== "[object Object]") { return false; } proto = getProto(obj); // 若是是對象可是沒有原型則是由 Object.create( null ) 建立 if (!proto) { return true; } // 原型的構造函數是 Object(),則爲計劃對象 Ctor = hasOwn.call(proto, "constructor") && proto.constructor; return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString; }
extend 代碼分析node
// extend 代碼分析 var jQuery = {}; /* jQuery.extend()函數用於將一個或多個對象的內容合併到目標對象。 jQuery.extend( [ deep ], target , object1 [, objectN... ] ) */ jQuery.extend = jQuery.prototype.extend = function () { // 定義後邊用到的變量 var options, name, src, copy, copyIsArray, clone, // 第一個參數爲目標對象 target = arguments[0] || {}, i = 1, length = arguments.length, // 是否爲深拷貝 deep = false; // 深度拷貝 /* 若是第一個參數爲布爾值則表明深拷貝 */ if (typeof target === "boolean") { deep = target; // Skip the boolean and the target 將第二個參數設置爲目標對象 target = arguments[i] || {}; i++; } // 參數不是對象的狀況 if (typeof target !== "object" && !isFunction(target)) { target = {}; } // 若是隻有一個參數或者兩個參數且第一個參數爲 deep 擴展自身 if (i === length) { target = this; i--; } for (; i < length; i++) { // 參數不是null 或者undefined /* null == undefined // true null == null // true */ if ((options = arguments[i]) != null) { // 擴展對象 for (name in options) { src = target[name]; copy = options[name]; /* target = {a:1,b:2} options = { test: target } target.test = target; //會出現沒法遍歷 */ if (target === copy) { continue; } // 判斷是深拷貝,且copy爲數組或者計劃對象 /* 計劃對象 { } new Object() */ if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { // 數組 if (copyIsArray) { copyIsArray = false; clone = src && Array.isArray(src) ? src : []; } else { // 對象 clone = src && jQuery.isPlainObject(src) ? src : {}; } // Never move original objects, clone them target[name] = jQuery.extend(deep, clone, copy); // Don't bring in undefined values // 若是拷貝值爲null/undefined 則不拷貝 } else if (copy !== undefined) { target[name] = copy; } } } } return target; };