Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jQuery源码阅读二 #38

Open
wuxianqiang opened this issue Jan 12, 2018 · 0 comments
Open

jQuery源码阅读二 #38

wuxianqiang opened this issue Jan 12, 2018 · 0 comments
Labels

Comments

@wuxianqiang
Copy link
Owner

wuxianqiang commented Jan 12, 2018

function DOMEval( code, doc ) {
		doc = doc || document;
		var script = doc.createElement( "script" );
		script.text = code;
		doc.head.appendChild( script ).parentNode.removeChild( script );
	}

DOMEval: 该方法通过动态创建一个script标签,然后把标签添加到页面中,把代码执行,然后移除script标签,该方法并没有使用eval,因为jQuery使用了严格模式use strict,在严格模式中不能使用eval,该方法就是等同于eval。参数说明:参数一是代码字符串,参数二是添加到页面的位置。

eq: function( i ) {
		var len = this.length,
			j = +i + ( i < 0 ? len : 0 );
		return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
	}

jQuery的原型中有个eq的方法,看上面的代码,我们发现它对参数的处理非常好,首先是+i把传入进来的参数i转换数值形式的,然后是判断i是正数还是负数,如果传入的是负数默认会与数组的长度相加得到正确的值。该方法使用了一个pushStack方法,我们看看该方法是干什么的?

pushStack: function( elems ) {
		var ret = jQuery.merge( this.constructor(), elems );
		ret.prevObject = this;
		return ret;
	},
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;
	},
end: function() {
		return this.prevObject || this.constructor();
	}
  1. pushStack是jQuery中的静态方法,使用传入的元素生成一个新的 jQuery 元素,注意该方法添加了属性prevObject 保留了this指向(this代表的是匹配元素集合),这样做是为什么?其实jQuery的很多方法里面都有return this这样的写法来实现链式调用,但是实现链式调用的前提要保证每一个return this都不能具有破坏性。如果某一个方法真的要修改匹配元素集合 , 那么它就会调用 pushStack 方法 , 把之前的元素集合保存起来 , 以便以后使用 end 方法恢复。

  2. 方法中的this.constructor()表示创建当前实例的函数,也就是jQuery本身,当jQuery本身执行的时候没有传入任何参数的情况下回会返回一个空对象,详细介绍在 jQuery源码阅读 #23

  3. merge方法是将连个数组拼接到一起,返回一个新的数组,注意当第一个参数传入jQuery函数的返回值时,length是在原型中被定义的,而且初始值为0

  4. end方法是恢复匹配元素集合的,继续实现链式调用

来分析一下jQuery是如何进行数据类型检测的,因为jQuery中代码都写在一个自执行函数里面,通过闭包的形式来隐藏变量。关于和判断数据类型的有关的有两部分代码。

var class2type = {};
var toString = class2type.toString;
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
function( i, name ) {
	class2type[ "[object " + name + "]" ] = name.toLowerCase();
} );

下面代码的往jQuery函数上拓展的静态方法

type: function( obj ) {
		if ( obj == null ) {
			return obj + "";
		}
		return typeof obj === "object" || typeof obj === "function" ? class2type[ toString.call( obj ) ] || "object" : typeof obj;
	},
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;
	},

通过上面的代码,我们发现jQuery将所有的数据类型都都保存在一个叫class2type 的变量中。each方法是将传入的数组或对象进行循环遍历并执行回调函数,type方法是判断数据类型的方法,我在这里详细解释一下,先判断传入进来的参数是不是nullundefined如果是就两个值就通过调用String()方法并返回,如果不是这两个值,然后再判断是不是objectfunction如果是将会把class2type 的变量存储的对应的数据类型返回,如果该变量没有对应的数据类型将会返回一个object,如果不是objectfunction类型将会继续使用typeof检测。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant