【jQuery源码浅析】(四)--jQuery工具--$.fn
来源:互联网 发布:c语言主函数参数 编辑:程序博客网 时间:2024/06/06 21:13
前言
jQuery的工具,顾名思义,就是直接可以以jQuery.do()
的方式去执行jQuery中的方法,其实就是jQuery的静态方法。
由于jQuery的静态方法比较多,我就抽出几个重要的工具方法来进行源码解读一下。主要有:$.isPlainObject、$.each、$.map、$.grep、$.proxy,下面我就来一一解读一下这几个工具的源码。
源码分析
—isPlainObject
该方法的用法请看$.isPlainObject
版本对比:
$.isPlainObject-v1.10.2源码请从这里下载查看
/********** v3.1.1 **********/62 var class2type = {}; var getProto = Object.getPrototypeOf; var hasOwn = {}.hasOwnProperty; var fnToString = hasOwn.toString; var ObjectFunctionString = fnToString.call( Object );302 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;321 }
对比小结:
- 整体实现都是一样的,旧版本做了一些兼容,最终判断方式是判断是否有非继承属性
core_hasOwn.call(obj, key)
,实现过程看这里$.isPlainObject实现原理 - 新版本的判断方式更为严谨一点,主要有两个判断,一是对象是否由new Object()或者{}而来,任何不是Object构造器的实例都不是plainObject,比如new Date()和window之类的;;;二是该对象的原型的构造器一定是function,如果是
var obj = {}; Object.setPrototypeOf(obj, { constructor: 'aa'} )
,那么这个obj也不是plainObject - 判断是否为Object的实例,由
fnToString.call( Ctor ) === ObjectFunctionString
判断;判断是否对象原型的构造器没有被重写,由typeof Ctor === "function"
判断 - Object.create(null)也是plainObject
—each
该方法的用法请看$.each
版本对比
$.each-v1.10.2源码请从这里下载查看
/********** v3.1.1 **********/362 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;381 }
对比小结
- 实现的功能都一样,遍历类数组或对象的属性,然后用callback来处理遍历到的属性。如果callback返回的是false,则终止遍历。不过1.x版本可以传入第三个参数args,作为callback的参数,但是代码写得有点赘余。
- 新版本不用传递args参数,已经确定好callback的只有两个参数,分别为index和element,得源于
callback.call( obj[ i ], i, obj[ i ] )
。 - callback里面的this是obj的属性值,因此可以用
this.prop = xxx
,这样来改变obj的属性值。 - 对象的遍历会遍历到父类的属性上面,得源于
for ( i in obj )
。 - 最后返回的是传入的对象本身
return obj
—map
该方法的用法请看$.map
与$.each的比较
/********** v3.1.1 **********/56 var concat = [].concat; // arg is for internal usage only448 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 );477 }
对比小结
- map不会终止遍历
- callback有三个参数,分别为element、index、arguments,得源于
value = callback( elems[ i ], i, arg )
- 如果callback返回的不是null,则将返回的value放入到最后返回的对象或数组的其中一段空间里面,
ret.push( value )
。最后返回的结果和call完全不一样,call是改造了原来的element,而map是重新创建一个element,我把这个element叫做dist,然后把每个element的每个属性值改造完后通过callback返回一个最终的属性值,把它加入dist里面,concat.apply( [], ret )
。也就是说,最终返回的肯定是数组,数组里面的值由callback的返回值决定。
—grep
该方法的用法请看$.grep
版本对比
$.grep-v1.10.2源码请从这里下载查看
/********** v3.1.1 **********/428 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;445 }
对比小结
- 首先我认为这个方法应该叫filter,这样就可以更直观地知道这个方法是用于过滤数组的。Array里面就有一个Array.filter的方法。
- 版本升级后有一点点改动,不过实现过程是几乎一样的,只不过旧版本多了一个判断
if (inv !== retVal)
而已。 - 原理很简单,就是根据invert的值来判断callback里面的值是否要被筛选出来。
- 当中有一个小技巧,`就是先把invert和callback用!转成boolean类型再比较,非常严谨。
—proxy
该方法的用法请看$.proxy
源码
484 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;509 }
源码分析
- 这个方法和function.prototype.bind()很像,都是指定function中的this所指的最终对象。但是proxy可以接收第二种参数列表的方式,即
proxy(context,fnName)
的方式,context也就是所需要绑定的obj,if ( typeof context === "string" ) { tmp = fn[ context ]; context = fn;fn = tmp;}
。 - 可接收除了这两个重要参数的其他参数
args = slice.call( arguments, 2 )
- 采用对象冒充的方式强制将fn的this指向所想要绑定的context身上
fn.apply( context || this, args.concat( slice.call( arguments ) ) )
,如果context不存在的话有可能是本身也有可能是window,取决于上下文环境。接收多个用于fn的参数args.concat( slice.call( arguments ) )
- 最终返回的类型是方法,即代理后的方法。
相关资料
- jQuery技术内幕:深入解析jQuery架构设计与实现原理
- this.method.apply(this,arguments)
用法解析 - jQuery3.1.1.js源码下载
阅读全文
1 0
- 【jQuery源码浅析】(四)--jQuery工具--$.fn
- JQuery源码浅析之工具-each
- jquery .fn
- jquery $.fn
- jQuery源码解析之jQuery.extend(),jQuery.fn.extend()
- Jquery---$.fn---jQuery.fn.extend
- jQuery源码分析-----jQuery.fn.init.prototype=jQuery.fn=jQuery.prototype
- JQuery源码浅析: Callbacks
- jQuery源码浅析
- jquery.fn jquery.extend jquery.fn.extend
- 【jQuery源码浅析】(一)--整体架构
- jQuery源码研究分析学习笔记-jQuery.fn.init()(五)
- jquery源码——jquery.fn.access()函数
- jQuery.extend()方法和jQuery.fn.extend()方法源码分析
- jQuery源码中的“new jQuery.fn.init()”什么意思?
- 【jQuery源码浅析】(二)--jQuery的构造--$()
- 【jQuery源码浅析】(三)--jQuery插件拓展--$.extend
- jquery-core-$(fn)、插件$.fn
- Python积累学习(一)ftp上传或下载操作
- CENTOS 安装nodejs
- bootstrap-treeview 后台拼装JSON
- 6. 如何看硬件原理图(pads)
- crond与crontab调研
- 【jQuery源码浅析】(四)--jQuery工具--$.fn
- tensorflow中CNN对mnist识别
- Android7.0运行app报SecurityException MODE_WORLD_READABLE
- 版本更新
- 拓扑排序(C语言 邻接表)
- JNI转换通俗易懂的总结(C++调用java篇)
- RNN与LSTM原理
- Spark核心编程:共享变量(Broadcast Variable和Accumulator)
- Java设计模式-命令模式