你真的懂jQuery吗?

jQuery创建实例对象及其原型上的方法扩展

jQuery创建实例对象中的参数selector

  • new jQuery.fn.init(selector, context);是调用jQuery原型上init方法创建一个jQuery实例对象(JQ对象)。
init = jQuery.fn.init = function (selector, context, root) {
			var match, elem;
			// HANDLE: $(""), $(null), $(undefined), $(false)
			if (!selector) {
				return this;
			}
			// Method init() accepts an alternate rootjQuery
			// so migrate can support jQuery.sub (gh-2101)
			root = root || rootjQuery;

			// Handle HTML strings
			if (typeof selector === "string") {
				if (selector[0] === "<" &&
					selector[selector.length - 1] === ">" &&
					selector.length >= 3) {

					// Assume that strings that start and end with <> are HTML and skip the regex check
					match = [null, selector, null];

				} else {
					match = rquickExpr.exec(selector);
				}

				// Match html or make sure no context is specified for #id
				if (match && (match[1] || !context)) {

					// HANDLE: $(html) -> $(array)
					if (match[1]) {
						context = context instanceof jQuery ? context[0] : context;

						// Option to run scripts is true for back-compat
						// Intentionally let the error be thrown if parseHTML is not present
						jQuery.merge(this, jQuery.parseHTML(
							match[1],
							context && context.nodeType ? context.ownerDocument || context : document,
							true
						));

						// HANDLE: $(html, props)
						if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
							for (match in context) {

								// Properties of context are called as methods if possible
								if (isFunction(this[match])) {
									this[match](context[match]);

									// ...and otherwise set as attributes
								} else {
									this.attr(match, context[match]);
								}
							}
						}

						return this;

						// HANDLE: $(#id)
					} else {
						elem = document.getElementById(match[2]);

						if (elem) {

							// Inject the element directly into the jQuery object
							this[0] = elem;
							this.length = 1;
						}
						return this;
					}

					// HANDLE: $(expr, $(...))
				} else if (!context || context.jquery) {
					return (context || root).find(selector);

					// HANDLE: $(expr, context)
					// (which is just equivalent to: $(context).find(expr)
				} else {
					return this.constructor(context).find(selector);
				}

				// HANDLE: $(DOMElement)
			} else if (selector.nodeType) {
				this[0] = selector;
				this.length = 1;
				return this;

				// HANDLE: $(function)
				// Shortcut for document ready
			} else if (isFunction(selector)) {
				return root.ready !== undefined ?
					root.ready(selector) :

					// Execute immediately if ready is not present
					selector(jQuery);
			}

			return jQuery.makeArray(selector, this);
		};

[selector] 根据传递的参数不同走不同的逻辑,最后都返回的是一个JQ对象

// HANDLE: $(""), $(null), $(undefined), $(false)
	if (!selector) {
		return this;
	}

当传递的参数selector为null、undefined、""、0、NaN、false时返回一个空JQ对象。

// ?:	只匹配不捕获
// \s* 	一个空白字符(包含空格、制表符、换页符)出现0到多次
// (<[\w\W]+>)  分组捕获中的第一个 <任意字符1到多次>
// [^>]*|#([\w-]+)  不为>的字符0到多次  或者 #数字、字母、下划线1到多次  
// ([\w-]+)分组捕获中的第二个
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,

/*
	如果传递的参数selector 是一个字符串
*/
if (typeof selector === "string") {
//这个字符串以"<"开头以">"结束并且字符串长度>=3    类似这种:"<a>"
				if (selector[0] === "<" &&
					selector[selector.length - 1] === ">" &&
					selector.length >= 3) {

//将字符串放到数组中且字符串索引为1
					match = [null, selector, null];

				} else {
//捕获正则中的第一个元素 捕获到的结果应该是["selector","分组捕获的第一个元素",...]
					match = rquickExpr.exec(selector);
				}

// match不为空且(match[1]不为空 或者 contex为空) match[1]:代表selector或分组捕获的第一个元素
				if (match && (match[1] || !context)) {

					// match[1]不为空
					if (match[1]) {
					//context 是jQuery的一个实例直返回context[0]否则返回context
						context = context instanceof jQuery ? context[0] : context;

						// Option to run scripts is true for back-compat
						// Intentionally let the error be thrown if parseHTML is not present
						jQuery.merge(this, jQuery.parseHTML(
							match[1],
							context && context.nodeType ? context.ownerDocument || context : document,
							true
						));

						// HANDLE: $(html, props)
						if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
							for (match in context) {

								// Properties of context are called as methods if possible
								if (isFunction(this[match])) {
									this[match](context[match]);

									// ...and otherwise set as attributes
								} else {
									this.attr(match, context[match]);
								}
							}
						}

						return this;

						// 说明是$("#id")这种方式 调用js的document.getElementById(match[2]); match[2]为正则捕获的id

					} else {
						elem = document.getElementById(match[2]);

						if (elem) {

							// 根据id获取的元素不为空,将元素放入到JQ对象中,返回 this指向JQ对象(是一个类数组)。 
							this[0] = elem;
							this.length = 1;
						}
						return this;
					}

					// HANDLE: $(expr, $(...))
				} else if (!context || context.jquery) {
					return (context || root).find(selector);

					// HANDLE: $(expr, context)
					// (which is just equivalent to: $(context).find(expr)
				} else {
					return this.constructor(context).find(selector);
				}

				// HANDLE: $(DOMElement)
			}

selector传入参数为string时:选择器(获取元素的类数组集合“$("#id")” 或 HTML字符串$("<aaa>")(创建DOM对象,返回JQ实例,也就是一个类数组集合)

//判断selector是原生的DOM元素对象
else if (selector.nodeType) {
				//同样是将字符串放入JQ对象中返回一个类数组
				this[0] = selector;
				this.length = 1;
				return this;
			}

原生的DOM元素对象:把原生DOM对象转换为JQ对象 目的是调用JQ原型上的方法

//判断selector是一个函数
 else if (isFunction(selector)) {
				return root.ready !== undefined ?
					root.ready(selector) : selector(jQuery);
			}

//=======================================ready
jQuery.fn.ready = function (fn) {

		readyList
			.then(fn)
			.catch(function (error) {
				jQuery.readyException(error);
			});

		return this;
	};

$(function(){}) 等同于$(document).ready(函数)
作用:
1.等待页面中的DOM结构都加载完成(DOMContentLoaded),就会触发执行函数;
2.当做闭包,防止全局变量污染;
当传入的是DOM元素、节点集合…:返回一个JQ实例对象(类数组集合)目的是为了可以调用JQ对象原型上的方法

//返回一个数组  把两个数组或者类数拼接在一起
return jQuery.makeArray(selector, this);
  • jQuery中的merge方法
// 合并数据/类数组:把两个集合拼接在一起「第一个集合中」,最后返回第一个集合
jQuery.merge = function merge(first, second) {
	//获取第二个数组/类数组中的length转换为number类型
    var len = +second.length,
        j = 0,
        i = first.length;
    for (; j < len; j++) {
    //将第二个数组/类数组中的值追加到第一个数组/类数组中,且改变length值
        first[i++] = second[j];
    }
    // 数组可以自动累加长度,但是类数组不会
    first.length = i;
    return first;
};
  • jQuery中的makeArray方法
// 把类数组转换为数组 $([类数组])
// 把两个数组或者类数拼接在一起
jQuery.makeArray = function makeArray(arr, results) {
//传入第二个参数为空是返回一个空数组
    var ret = results || [];
    if (arr != null) {
        if (isArrayLike(Object(arr))) {
            jQuery.merge(ret,
                typeof arr === "string" ? [arr] : arr
            );
        } else {
            // 在不清楚是数组还是类数组集合的时候,我们尽可能使用 [].xxx.call(xxx) 借用的方法来调用数组的方法
            // 不考虑兼容以及结构是否变化的情况下,也可以Array.from(xxx)都变为数组 
            [].push.call(ret, arr);
        }
    }
    return ret;
};
  • jQuery中的each方法
//遍历数组/类数组/对象中的每一项
jQuery.each = function each(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;
		},

/*
//改良版
 var each = function each(obj, callback) {
        var length,
            i = 0,
            item,
            index,
            result,
            keys;
        if (isArrayLike(obj)) {
            length = obj.length;
            for (; i < length; i++) {
                item = obj[i];
                index = i;
                result = callback.call(item, item, index);
                // 我们处理了FOR-EACH不支持的“循环结束的控制方式”:回调函数返回false
                if (result === false) break;
            }
        } else {
            // 我们考虑FOR IN的BUG
            if (obj == null) throw new TypeError('obj not be a null/undefined!');
            keys = Object.keys(obj);
            typeof Symbol !== "undefined" ? keys = keys.concat(Object.getOwnPropertySymbols(obj)) : null;
            length = keys.length;
            for (; i < length; i++) {
                index = keys[i];
                item = obj[index];
                result = callback.call(item, item, index);
                if (result === false) break;
            }
        }
        return obj;
    };
*/
  • jQuery中的pushStack方法
  • jQuert中 $(xxx).get([index])和$(xxx).eq([index]) get方法和eq方法的区别:
// 原型方法:供实例调用

jQuery.fn = jQuery.prototype = {
    jquery: version,
    constructor: jQuery,
    // 支持负数索引/不传递索引
    get: function (num) {
        if (num == null) {
            return slice.call(this);
        }
        return num < 0 ? this[num + this.length] : this[num];
    },
    eq: function (i) {
        var len = this.length,
            j = +i + (i < 0 ? len : 0);
        return this.pushStack(j >= 0 && j < len ? [this[j]] : []);
    },
    //给JQ对象增加了一个prevObject属性方便操作DOM找到初始状态
    pushStack: function (elems) {
        var ret = jQuery.merge(this.constructor(), elems);
        ret.prevObject = this;
        return ret;
    },
    //直接拿数组的方法来用
    push: push,
    sort: arr.sort,
    splice: arr.splice,
    //...
};

get 和eq 方法都是把JQ对象(一般类数组集合) 转换为 原生DOM对象:可以调用浏览器提供的内置的属性和方法。 基于JQ集合中的某个索引获取即可 $(xxx)[index] ->DOM对象。
$(xxx).get([index]) 返回的是 原生DOM对象
$(xxx).eq([index]) 返回的是 新的JQ实例对象可以继续.addClass调用JQ对象原型上的方法。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值