jquery源码解析:proxy,access,swap,isArraylike详解
jQuery的工具方法,其实就是静态方法,源码里面就是通过extend方法,把这些工具方法添加给jQuery构造函数的。
jQuery.extend({
......
guid: 1,
//唯一标识符,跟事件有关。举个例子:function show(){alert(this);}, $("#input1").click(show),$("#input2").click(function(){$("#input1").off()}),这里的show方法是事件方法,所以通过off取消掉事件绑定,可以很容易找到事件方法show。但是如果把 $("#input1").click(show)改成 $("#input1").click($.proxy(show,window)),这时show不是事件方法,而是普通方法,那么通过off取消的时候,它是怎么找到这个普通方法show的,其实就是通过guid,因为guid会累加,所以是唯一的,因此可以找到。请看下个方法就知道详情了。
proxy: function( fn, context ) {
//改变方法(函数)执行的this指向。举例:$.proxy(show,document),想给show传参的话,有两种方式:var fn = $.proxy(show,document,1,2);fn(3,4)。最终show执行时就会变成show(1,2,3,4),proxy返回一个函数,调用fn时,就会执行show方法。
var tmp, args, proxy;
if ( typeof context === "string" ) { //这里处理特殊调用情况,比如:$.proxy(obj,"show")(正常写法$.proxy(obj.show,obj)),show方法执行时,this指向的obj,并且show是obj的属性方法.var obj = { show: function(){}}。
tmp = fn[ context ];
context = fn;
fn = tmp;
}
if ( !jQuery.isFunction( fn ) ) {
return undefined;
}
args = core_slice.call( arguments, 2 ); //传入的参数,相当于例子的[1,2]
proxy = function() {
return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) ); //把[3,4]和[1,2]合并成[1,2,3,4]
};
proxy.guid = fn.guid = fn.guid || jQuery.guid++;
//第一次时,fn.guid(show.guid)是undefined,proxy.guid = fn.guid = 1,show.guid =1,
//function() {return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) )}.guid=1,唯一标识,取消绑定时,可以用到。
return proxy;
},
//$().css(),$().attr(),通过参数的不同,实现get/set。参数的个数,以及参数的类型。$("div").css("width"),获得第一个div元素的width,$("div").css("width",100)设置所有的div元素的width。$("div").css({width:100,height:200}),也是设置所有的div元素,尽管只有一个参数,但是类型不一样。JQuery中有很多这种方法,所以统一用access实现。
access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
//elems操作的元素,可能是一个集合。fn是一个回调函数(有区别的在回调函数中处理,比如,css设置样式,attr设置属性)。key和value就是属性名和属性值。chainable为true,设置,为false就获取。
var i = 0,
length = elems.length,
bulk = key == null;
if ( jQuery.type( key ) === "object" ) {//处理这种类型$("div").css({width:100,height:200})
chainable = true;
for ( i in key ) {
jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
}
}
else if ( value !== undefined ) { //处理这种$("div").css("width",100)
chainable = true;
if ( !jQuery.isFunction( value ) ) {
raw = true; //字符串(数字)时
}
if ( bulk ) { //如果没有key值
if ( raw ) { //如果value是字符串(数字)
fn.call( elems, value ); //调用回调方法
fn = null; //把回调方法赋为空
}
else { //如果是函数,这里面的不用深入理解
bulk = fn;
fn = function( elem, key, value ) {
return bulk.call( jQuery( elem ), value );
};
}
}
if ( fn ) { //如果没有key值,并且value是字符串(数字),这里就为null,不会执行
for ( ; i < length; i++ ) {
fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
}
}
}
return chainable ? //获取时,chainable为false
elems : //设置时,chainable为true,直接返回元素,进行后续的链式操作
bulk ?
fn.call( elems ) : //没有key值时,就回调
length ? fn( elems[0], key ) : emptyGet; //有key值时,判断元素有没有元素,有的话就获取第一个元素的key值(属性名的值),没有元素的话,就返回emptyGet。
},
now: Date.now, //当前时间距离1970年的毫秒数,相当于(new Date()).getTime()
//以下方法是处理这种情况的:
//<div id="div1" style="width:100px;height:100px;background:red;display:none;">ddd</div>
$("#div1").get(0).offsetWidth取到的是0,因为它是display:none,不存在DOM树中。$("#div1").width()取到的是100,为啥jQuery可以。因为jQuery会对display:none的元素进行处理,变成<div id="div1" style="width:100px;height:100px;background:red;display:block;visibility:hidden;position:absolute">ddd</div>,这里就可以通过$("#div1").get(0).offsetWidth取到100了,然后再把新添加的样式去掉。
swap: function( elem, options, callback, args ) { //css的转换,内部使用
var ret, name,
old = {};
for ( name in options ) {
//保存老样式,插入新样式。这里假设options={width:100px;height:100px;background:red;display:block;visibility:hidden;position:absolute}
//elem.style = {width:100px;height:100px;background:red;display:none;}
old[ name ] = elem.style[ name ];
elem.style[ name ] = options[ name ];
}
ret = callback.apply( elem, args || [] );
//通过插入的新样式来获取元素的css值,callback = function(args){ if(args不是[]) return this[args]},args= offsetWidth;
for ( name in options ) { //恢复老样式
elem.style[ name ] = old[ name ];
}
return ret;
}
......
})
最后讲一下这个方法:
function isArraylike( obj ) {//判断是否是数组,类数组,带length的json,是的话就返回真
var length = obj.length,
type = jQuery.type( obj );
if ( jQuery.isWindow( obj ) ) { //担心window对象有length属性
return false;
}
if ( obj.nodeType === 1 && length ) {
//元素节点对象,并且有length属性,返回真。document.getElementsByTagName("div")和body.childNodes都不是这种情况。可能用于内部调用,这里如果有谁知道的,可以告诉我。
return true;
}
return type === "array" || type !== "function" && //不能是函数,因为函数也可能有length属性
( length === 0 ||typeof length === "number" && length > 0 && ( length - 1 ) in obj );
//typeof length === "number" && length > 0 && ( length - 1 ) in obj )处理{0:"a",1:"b",length:2}这种情况。length === 0处理arguments为空的时候,就是不传入函数任何数据,这时函数中的arguments的length为0,但是是类数组。document.getElementsByTagName("div")和body.childNodes也是类数组。
}
加油!
jquery源码解析:proxy,access,swap,isArraylike详解的更多相关文章
- gulp源码解析(一)—— Stream详解
作为前端,我们常常会和 Stream 有着频繁的接触.比如使用 gulp 对项目进行构建的时候,我们会使用 gulp.src 接口将匹配到的文件转为 stream(流)的形式,再通过 .pipe() ...
- jQuery 源码分析(十八) ready事件详解
ready事件是当DOM文档树加载完成后执行一个函数(不包含图片,css等),因此它的触发要早于load事件.用法: $(document).ready(fun) ;fun是一个函数,这样当DOM树加 ...
- jQuery 源码分析(十一) 队列模块 Queue详解
队列是常用的数据结构之一,只允许在表的前端(队头)进行删除操作(出队),在表的后端(队尾)进行插入操作(入队).特点是先进先出,最先插入的元素最先被删除. 在jQuery内部,队列模块为动画模块提供基 ...
- Linux源码解析-内核栈与thread_info结构详解
1.什么是进程的内核栈? 在内核态(比如应用进程执行系统调用)时,进程运行需要自己的堆栈信息(不是原用户空间中的栈),而是使用内核空间中的栈,这个栈就是进程的内核栈 2.进程的内核栈在计算机中是如何描 ...
- Spring源码解析--IOC根容器Beanfactory详解
BeanFactory和FactoryBean的联系和区别 BeanFactory是整个Spring容器的根容器,里面描述了在所有的子类或子接口当中对容器的处理原则和职责,包括生命周期的一些约定. F ...
- AngularJS源码解析2:注入器的详解
上一课,没有讲createInjector方法,只是讲了它的主要作用,这一课,详细来讲一下这个方法.此方法,最终返回的注册器实例对象有以下几个方法: invoke, instantiate, get, ...
- hanlp源码解析之中文分词算法详解
词图 词图指的是句子中所有词可能构成的图.如果一个词A的下一个词可能是B的话,那么A和B之间具有一条路径E(A,B).一个词可能有多个后续,同时也可能有多个前驱,它们构成的图我称作词图. 需要稀疏2维 ...
- axios 源码解析(下) 拦截器的详解
axios的除了初始化配置外,其它有用的应该就是拦截器了,拦截器分为请求拦截器和响应拦截器两种: 请求拦截器 ;在请求发送前进行一些操作,例如在每个请求体里加上token,统一做了处理如果以后要 ...
- JQuery源码解析(一)
写在前面:本<JQuery源码解析>系列是基于一些前辈们的文章进行进一步的分析.细化.修改而写出来的,在这边感谢那些慷慨提供科普文档的技术大拿们. 要查阅JQ的源文件请下载开发版的JQ.j ...
- jQuery 源码解析二:jQuery.fn.extend=jQuery.extend 方法探究
终于动笔开始 jQuery 源码解析第二篇,写文章还真是有难度,要把自已懂的表述清楚,要让别人听懂真的不是一见易事. 在 jQuery 源码解析一:jQuery 类库整体架构设计解析 一文,大致描述了 ...
随机推荐
- GLSL in ShaderLab
[Syntax] However, use of raw GLSL is only recommended for testing, or when you know you will only ta ...
- Scala基础:模式匹配和样例类
模式匹配 package com.zy.scala import scala.util.Random /** * 模式匹配 */ object CaseDemo { def main(args: Ar ...
- java tomcat报错: Starting Tomcat v7.0 Server at localhost' has encountered a problem问题
运行web项目的时候出现下面错误: 出现这个问题的原因是 这个tomcat在其他项目中正在运行 关掉即可.
- iOS单选和全选
在日常开发中单选.多选.全选经常遇到,所以写一个demo放上来供大家参考, 先看效果图: Demo地址:https://github.com/domanc/SingleAndAllSelect.git
- 对图片进行X,Y轴的翻转,黑白色转变
做完了修改图片的程序.用的Winfrom做的.昨天基本完成,记录一下使用的东西. 首先是将需要加载的图片放入picturebox控件,这里用到了openfiledialog 打开文件对话框 strin ...
- SQLSERVER Tempdb的作用及优化
tempdb 系统数据库是可供连接到 SQL Server 实例的所有用户使用的全局资源.tempdb 数据库用于存储下列对象:用户对象.内部对象和版本存储区. 用户对象 用户对象由用户显式创建.这些 ...
- Openssl ec命令
一.简介 椭圆曲线密钥处理工具 二.语法 openssl ec [-inform PEM|DER] [-outform PEM|DER] [-in filename] [-out filename] ...
- OpenCV学习记录(二):自己训练haar特征的adaboost分类器进行人脸识别 标签: 脸部识别opencv 2017-07-03 21:38 26人阅读
上一篇文章中介绍了如何使用OpenCV自带的haar分类器进行人脸识别(点我打开). 这次我试着自己去训练一个haar分类器,前后花了两天,最后总算是训练完了.不过效果并不是特别理想,由于我是在自己的 ...
- 冲刺NOIP2015提高组复赛模拟试题(五)1.数学作业
1. 数学作业 [问题描述] 路人丙的数学老师非常乏力,他喜欢出一些非常乏力的数学题来为难乏力的学生们.这次数学老师布置了一堆的数学题作为作业,而且这些数学题有个共同的特点是都求C(N,M)中不同质因 ...
- 用Spring实现文件上传(CommonsMultipartFile)!
2012-02-16 18:10:26| 分类: 计算机--JAVA EE-|字号 订阅 spring中的文件上传实际比较容易1.页面中<html> <body> & ...