菜鸡看jquery源码(3)extend
来源:互联网 发布:威可多和雅戈尔 知乎 编辑:程序博客网 时间:2024/06/07 09:28
extend是jquery常用的一个方法,虽然原生用Object.assign实现了类似的功能。
jQuery.extend = jQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone, target = arguments[ 0 ] || {}, //从arguments里拿第一个参数,没传就给默认空对象 i = 1, length = arguments.length,//参数长度 deep = false;//默认不是深拷贝 // Handle a deep copy situation //处理深拷贝的情况 if ( typeof target === "boolean" ) { deep = target; // Skip the boolean and the target target = arguments[ i ] || {}; i++; } //判断传参情况,首先target取的是第一个参数,如果target是个布尔值,说明传入了是否深拷贝的布尔值,用argument[1]取到第二个参数给target // Handle case when target is a string or something (possible in deep copy) //处理目标值为字符串或者其他值情况 if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { target = {}; } //简言之,不是对象就给target一个默认空对象 // Extend jQuery itself if only one argument is passed //如果就传了一个参数就继承自身 if ( i === length ) { target = this; i--; } //这里的this指向jQuery for ( ; i < length; i++ ) { //第一层循环遍历传入的需要合并的参数对象 //为了方便观察,假设传入 extend(target,obj1,obj2,obj3)传入的第一个参数不是布尔值,所以i值为初始化的1; // Only deal with non-null/undefined values //只处理非空值 if ( ( options = arguments[ i ] ) != null ) { //对传入的在target后的每一个对象进行遍历 // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; //target的属性值放进src里,options的属性值放进copy里 // Prevent never-ending loop //阻止死循环 if ( target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject( copy ) || ( copyIsArray = Array.isArray( copy ) ) ) ) { //判断拿到的copy是否为对象或数组并且传入的第一个参数为true则深拷贝,继续深入遍历 if ( copyIsArray ) { //如果是数组,将copyIsArray重新变为false方便后面遍历的判断,并判断target对象对应的该属性是否为数组,是就赋值给clone,否则赋值空数组 copyIsArray = false; clone = src && Array.isArray( src ) ? src : []; } else { //和上面处理数组一样处理这里面的对象 clone = src && jQuery.isPlainObject( src ) ? src : {}; } // Never move original objects, clone them //用前面拿到的clone和copy调用函数自身,实现一层一层进去复制,这里调用自身来做深拷贝很精妙 target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { //如果不是深拷贝就好办了,直接把后面的对象对应的属性覆盖的target中对应的属性 target[ name ] = copy; } } } } // Return the modified object //最后把这个修改过的对象传出去 return target;};
jquery的extend实现很巧妙,在其源码自身多处用到了这个方法,理解这个方法对后续的源码阅读有很大的帮助。
定义完extend后,直接使用extend方法在jquery自身上拓展一些工具类方法和属性,具体方法的实现以及意义暂时忽略不讲,先把源码整体思路理通顺,后续可能会将比较有学习意义的方法拿出来再看看。有意思的一点是在定义extend函数时用到的isFunction、isPlainObject等方法在jquery调用extend函数给自身添加方法时才加上,有点奇怪。
jQuery.extend( { // Unique for each copy of jQuery on the page expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), // Assume jQuery is ready without the ready module isReady: true, error: function( msg ) { throw new Error( msg ); }, noop: function() {}, isFunction: function( obj ) { return jQuery.type( obj ) === "function"; }, isWindow: function( obj ) { return obj != null && obj === obj.window; }, isNumeric: function( obj ) { // As of jQuery 3.0, isNumeric is limited to // strings and numbers (primitives or objects) // that can be coerced to finite numbers (gh-2662) var type = jQuery.type( obj ); return ( type === "number" || type === "string" ) && // parseFloat NaNs numeric-cast false positives ("") // ...but misinterprets leading-number strings, particularly hex literals ("0x...") // subtraction forces infinities to NaN !isNaN( obj - parseFloat( obj ) ); }, isPlainObject: function( obj ) { var proto, Ctor; // Detect obvious negatives // Use toString instead of jQuery.type to catch host objects if ( !obj || toString.call( obj ) !== "[object Object]" ) { return false; } proto = getProto( obj ); // Objects with no prototype (e.g., `Object.create( null )`) are plain if ( !proto ) { return true; } // Objects with prototype are plain iff they were constructed by a global Object function Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; }, isEmptyObject: function( obj ) { /* eslint-disable no-unused-vars */ // See https://github.com/eslint/eslint/issues/6125 var name; for ( name in obj ) { return false; } return true; }, type: function( obj ) { if ( obj == null ) { return obj + ""; } // Support: Android <=2.3 only (functionish RegExp) return typeof obj === "object" || typeof obj === "function" ? class2type[ toString.call( obj ) ] || "object" : typeof obj; }, // Evaluates a script in a global context globalEval: function( code ) { DOMEval( code ); }, // Convert dashed to camelCase; used by the css and data modules // Support: IE <=9 - 11, Edge 12 - 13 // Microsoft forgot to hump their vendor prefix (#9572) camelCase: function( string ) { return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); }, each: function( obj, callback ) { var length, i = 0; if ( isArrayLike( obj ) ) { length = obj.length; for ( ; i < length; i++ ) { if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { break; } } } else { for ( i in obj ) { if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { break; } } } return obj; }, // Support: Android <=4.0 only trim: function( text ) { return text == null ? "" : ( text + "" ).replace( rtrim, "" ); }, // results is for internal usage only makeArray: function( arr, results ) { var ret = results || []; if ( arr != null ) { if ( isArrayLike( Object( arr ) ) ) { jQuery.merge( ret, typeof arr === "string" ? [ arr ] : arr ); } else { push.call( ret, arr ); } } return ret; }, inArray: function( elem, arr, i ) { return arr == null ? -1 : indexOf.call( arr, elem, i ); }, // Support: Android <=4.0 only, PhantomJS 1 only // push.apply(_, arraylike) throws on ancient WebKit merge: function( first, second ) { var len = +second.length, j = 0, i = first.length; for ( ; j < len; j++ ) { first[ i++ ] = second[ j ]; } first.length = i; return first; }, grep: function( elems, callback, invert ) { var callbackInverse, matches = [], i = 0, length = elems.length, callbackExpect = !invert; // Go through the array, only saving the items // that pass the validator function for ( ; i < length; i++ ) { callbackInverse = !callback( elems[ i ], i ); if ( callbackInverse !== callbackExpect ) { matches.push( elems[ i ] ); } } return matches; }, // arg is for internal usage only map: function( elems, callback, arg ) { var length, value, i = 0, ret = []; // Go through the array, translating each of the items to their new values if ( isArrayLike( elems ) ) { length = elems.length; for ( ; i < length; i++ ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret.push( value ); } } // Go through every key on the object, } else { for ( i in elems ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret.push( value ); } } } // Flatten any nested arrays return concat.apply( [], ret ); }, // A global GUID counter for objects guid: 1, // Bind a function to a context, optionally partially applying any // arguments. proxy: function( fn, context ) { var tmp, args, proxy; if ( typeof context === "string" ) { tmp = fn[ context ]; context = fn; fn = tmp; } // Quick check to determine if target is callable, in the spec // this throws a TypeError, but we will just return undefined. if ( !jQuery.isFunction( fn ) ) { return undefined; } // Simulated bind args = slice.call( arguments, 2 ); proxy = function() { return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); }; // Set the guid of unique handler to the same of original handler, so it can be removed proxy.guid = fn.guid = fn.guid || jQuery.guid++; return proxy; }, now: Date.now, // jQuery.support is not used in Core but other projects attach their // properties to it so it needs to exist. support: support} );
阅读全文
0 0
- 菜鸡看jquery源码(3)extend
- jQuery 源码学习(一)jQuery.extend()
- jquery源码-jquery.extend()
- jQuery源码-jQuery.extend
- jquery.extend源码分析
- jQuery.extend()源码解析
- 【jQuery源码浅析】(三)--jQuery插件拓展--$.extend
- jQuery源码阅读(八)---jQuery中的继承extend
- jQuery源码分析-extend函数
- jQuery.extend函数源码详解
- jQuery中extend()源码分析
- jQuery源码解析之jQuery.extend(),jQuery.fn.extend()
- jQuery源码解析--插件接口设计($.extend)
- 浅谈jQuery源码(八)——$.extend
- jQuery.extend()方法和jQuery.fn.extend()方法源码分析
- jQuery源码分析10: jQuery.extend
- jquery源码阅读之jquery.extend
- jQuery.extend ($.extend) 的使用
- XYNU OJ 1100—1109基础题(适合于C语言初学者)
- HDU1040
- Python性能加速
- [2-SAT]NOI2017 .day2 T1 游戏
- ionic2创建子module
- 菜鸡看jquery源码(3)extend
- 导弹力学分析_2
- ORA-12504
- 网络爬虫初识:网络爬虫概述
- JavaSE编程基础 第二章 数据类型和运算符
- MySQL入门之大纲
- dos命令之 chcp 用法详解(修改dos窗口的编码表(代码页))
- c++构造函数成员初始化赋值和初始化列表
- Mac OSX下编译 Hadoop 2.6.4