无 new 构建实例
$
是 jQuery 的别称,$()
是创建 jQuery 的实例对象
jQuery
选择一个折中的方案,当调用 $()
时,就会在 jQuery
原型上面的 jQuery.prototype.init
方法,把 init
方法当做构造函数返回实际的对象;现在想要创建 jQuery
的实例对象,但是在 jQuery
原型上面扩展的方法也会被继承;jQuery
用到一个共享原型的设计,让 jQuery
原型对象的 init
方法和 jQuery
共享
jQuery.prototype.init
作为构造函数,因为有共享原型对象的存在,jQuery.prototype.init.prototype
指向 jQuery.prototype
,所以 jQuery.prototype.init
构造的对象也指向 jQuery
$()
创建的是 jQuery
原型上 init
的实例对象,并不是 jQuery
的实例对象,但是 jQuery
和 jQuery.prototype.init
共享原型,所以 $()
指向 jQuery
源码解析
!(function (root) {
let jQuery = function () {
return new jQuery.prototype.init()
}
jQuery.prototype = {
init:function (){},
}
// 共享原型对象
jQuery.prototype.init.prototype = jQuery.prototype
root.$ = root.jQuery = jQuery
})(this)
extend 方法
功能
1. 外部使用:将两个或者更多个对象合并到第一个对象
jQuery.extend(target, object1 [,objectN])
,返回合并后的 target
// 浅拷贝,常用的插件开发模式
let defaults = { validate: false, limit: 5, name: "foo" };
let options = { validate: true, name: "bar" };
let settings = $.extend({}, defaults, options);
// 深拷贝
let object1 = {
apple: 0,
banana: {weight: 52, price: 100},
cherry: 97
};
let object2 = {
banana: {price: 200},
durian: 100
};
/* merge object2 into object1, recursively */
$.extend(true, object1, object2);
2. 内部使用:扩展 jQuery
自身
$.extend({
foo:function(){}
})
jQuery.foo()
扩展 jQuery
实例对象
$.fn.extend({
sex:"female"
})
$().sex //female
源码实现
extend
方法可以通过 $.extend
和 $.fn.extend
两种方式调用,二者实际上调用的是同一个函数
// extend
jQuery.fn.extend = jQuery.extend = function () {
// 获取目标
let target = arguments[0] || {}
// 获取参数长度
let length = arguments.length
// 参数数组索引
let i = 1
// target的扩展定义为option
let option
// 判断深拷贝
let deep = false
// 用于拆分浅拷贝和深拷贝
let copy, src
// 判断数组类型
let copyIsArray
// 用于递归运算
let clone
if (typeof target === "boolean") {
deep = target
target = arguments[1] || {}
++i
}
// 当目标对象值类型错误,则重置为{}
if (typeof target !== "object") {
target = {}
}
// 参数长度为1时,目标对象为自身
if (length === i) {
target = this
--i
}
// 浅拷贝
for (; i < length; i++) {
option = arguments[i]
// 忽略null 和 undefined
if ((options = arguments[ i ]) != null) {
for (let key in option) {
// 保存复制值,因此扩展jquery自身只能在copy之后使用
copy = option[key]
// 保存目标对象自身值
src = target[key]
// 防止环引用
if ( target === copy ) {
continue;
}
if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
if (copyIsArray) {
// 重置数组判断标志
copyIsArray = false
clone = src && jQuery.isArray(src) ? src : []
} else {
clone = src && jQuery.isPlainObject(src) ? src : {}
}
// 递归复制
target[key] = jQuery.extend(deep, clone, copy)
} else if (copy !== undefined && copy !== null) {
// 浅复制
target[key] = copy
}
}
}
}
return target
}
// 共享原型对象
jQuery.fn.init.prototype = jQuery.fn
// jQuery 扩展
jQuery.extend({
isPlainObject: function (args) {
return Object.prototype.toString.call(args) === "[object Object]"
},
isArray: function (args) {
return toString.call(args) === "[object Array]"
},
isVoid: function (args) {
return args === undefined || args === null || args === ''
}
})
网友评论