jQuery源码分析
(function (global, factory) {
"use strict"
/*
global:在浏览器&webpack环境下,global是window,在Node环境下,global是Global全局对象/模块
factory:传递的callback
*/
if (typeof module === "object" && typeof module.exports === "object") {
// JQ代码是在支持CommonJS规范「Node&Webpack」的环境下运行
module.exports = global.document ?
// 在webpack环境下运行:把 factory 执行的结果,基于 module.exports 导出
// --> module.exports = jQuery
// --> const $ = require('jquery') $就是导出的这个jQuery函数
factory(global, true) :
// 在Node环境下运行:JQ是不支持在Node环境下运行的
// --> const $ = require('jquery')
// --> $('box')
function (w) {
if (!w.document) {
throw new Error("jQuery requires a window with a document");
}
return factory(w);
}
} else {
// 在浏览器端运行:把factory执行
// --> <script src='js/jquery.min.js'>
factory(global)
}
})(
typeof window !== "undefined" ? window : this,//这里可看下图 node环境下无window
//==========================================↗↗↗↗↗↗↑↑↑↑↑↑↑↑↑↑↑↑↑↖↖↖↖↖↖↖
function (window, noGlobal) {
/*
进入这里只有两种情况:
1. 在浏览器下运行
window->window对象
noGlobal->undefined
2. 在webpack下运行
window->window对象
noGlobal->true
*/
"use strict"
/* 构造函数 */
var jQuery = function (selector, context) {
return new jQuery.fn.init(selector, context)
}
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
// ...
}
var init = jQuery.fn.init = function (selector, context, root) {
// ...
}
init.prototype = jQuery.fn
/*
$() / jQuery() -> 创造 jQuery 类的实例「可以调用 jQuery.prototype 上提供的属性方法」
问题:它是如何做到,把函数当做普通函数执行(没有带new),最后还创建了自己这个类的一个实例?
它用到了“工厂设计模式「中转类」”
+ $() 首次创建的是 init 这个类的一个实例
+ init.prototype = jQuery.prototype
+ 创建的实例就相当于 jQuery 类的实例
*/
/* 暴露API */
// 对AMD模块化思想的支持
if (typeof define === "function" && define.amd) {
define("jquery", [], function () {
return jQuery
})
}
// 在浏览器下运行
if (typeof noGlobal === "undefined") {
window.jQuery = window.$ = jQuery
}
// 支持 webpack 基于 module.exports 导出
return jQuery
}
)
/*
let arr = [10, 20, 30]
arr.push(40)
console.log(arr)
*/
const push = [].push // Array.prototype.push
let arr = [10, 20, 30]
push.call(arr, 40)
![{29FR$UYHZZ5K1(F}LDI3B_tmb.jpg
仿照jQuery源码处理utils.js文件
(function (global, factory) {
"use strict"
if (typeof module === 'object' && typeof module.exports === 'object') {
//node or webpack environments
module.exports = factory(global, true)
return
}
//browser environments
factory(global)
})(
typeof window !== "undefined" ? window : this,
function factory(window, noGlobal) {
"use strict"
//检测是否为函数
const isFunction = function isFunction(obj) {
return typeof obj === 'function'
}
//笼统校验是否为对象
const isObject = function isObject(obj) {
return obj !== null && /^(object|function)$/.test(typeof obj)
}
// 获取对象所有私有成员「兼容到IE、不受枚举和类型的限制」
const ownKeys = function ownKeys(obj) {
if (!isObject(obj)) throw new TypeError('传递的obj不是一个对象')
let keys = Object.getOwnPropertyNames(obj)
if (typeof Symbol !== 'undefined') {
keys = keys.concat(Object.getOwnPropertySymbols(obj))
}
return keys
}
//给对象新增一个不可枚举的成员(可删除可修改)
const def = function define(obj, key, value) {
Object.defineProperty(obj, key, {
value,//"value":value | value:value
writable: true,
configurable: true,
enumerable: false
})
}
/* 暴露API */
const utils = {
isFunction,
isObject,
ownKeys,
def
}
if (typeof define === "function" && define.amd) {
define("utils", [], function () {
return utils
})
}
if (typeof noGlobal === "undefined") {
window.utils = window._ = utils
}
return utils
}
)
//检测是否为函数
const isFunction = function isFunction(obj) {
return typeof obj === 'function'
}
//笼统校验是否为对象
const isObject = function isObject(obj) {
return obj !== null && /^(object|function)$/.test(typeof obj)
}
//获取对象所有私有成员(兼容IE、不受枚举和类型限制)
/* const ownKeys = function ownKeys(obj) {
// 确保传递的是对象
if (!isObject(obj)) throw new TypeError('传递的obj不是一个对象')
// 验证是否支持Reflect
if (typeof Reflect !== 'undefined') return Reflect.ownKeys(obj)
return Object.getOwnPropertyNames(obj)
} */
// 获取对象所有私有成员「兼容到IE、不受枚举和类型的限制」
const ownKeys = function ownKeys(obj) {
if (!isObject(obj)) throw new TypeError('传递的obj不是一个对象')
let keys = Object.getOwnPropertyNames(obj)
if (typeof Symbol !== 'undefined') {
keys = keys.concat(Object.getOwnPropertySymbols(obj))
}
return keys
}
//给对象新增一个不可枚举的成员(可删除可修改)
const def = function define(obj, key, value) {
Object.defineProperty(obj, key, {
value,//"value":value | value:value
writable: true,
configurable: true,
enumerable: false
})
}