实现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; };