jQuery源码分析--框架分析

jQuery源码分析

1. 所有的插件必须包含在一个闭包中

  1. 为了避免全局变量气污染
  2. 防止内部变量被外部调用
//插件主要运用了闭包的保护和保存机制 
(function( global, factory ) {
	// global -> 在浏览器环境下运行(或者webview等)它的值是window,在NODE环境下运行值可能是global
	"use strict";//开启严格模式,只管控当前函数使用严格模式,函数之外不是严格模式。
	// ...	

//利用js暂时性死区机制“基于typeof检测一个未被声明的变量,结果是undefined”:如果是在浏览器或者webview环境下运行JS,则A=window,如果是在Node环境下执行,则A=global或者当前模块。
})(typeof window !== "undefined" ? window : this,function factory( window, noGlobal){
	//...
})

JS运行环境

  • 浏览器 this => window
  • Hybrid -> webview
  • NODE : 不存在window typeof window = "undefined"

globa:利用typeof检测的暂时性死区机制判断当前环境是否支持window,支持global等于window,不支持则global等于this;
factory : 回调函数,把函数作为实参传递给另一个函数。

2. commonJS的模块导入导出规范

  • WEBPACK 环境
    • 支持 CommonJS/ ES6Module规范
    • 打包后的内容是放在浏览器中运行的,也是有window
  • 纯NODE 环境下运行
    • 不支持ES6Module规范,只支持commonJS规范
    • 里面没有window
  • 直接在浏览器环境下运行:<script src='xxx.js'></script>
    • 不支持 CommonJS/ ES6Module规范
    • 但是有window
    • scripttype 属性值为 module 时,新版本浏览器可以支持ES6Module规范
  • commonJS导出导入规范:
    • A : module.exports = { fn(){}, ... } //模块导出
    • B :let B = require("./A") ; B.fn(); // 模块导入
  • ES6Module导入导出法规范 ,
    • A: export default {fn(){}};
    • B:import A from ". / A"; A.fn() ;
(function( global, factory ) {
	"use strict";	
	if ( typeof module === "object" && typeof module.exports === "object" ) {
		 // 支持CommonJS模块的导入导出规范「NODE OR WEBPACK」
         // global.document 存在说明是WEBPACK环境「global->window」
		module.exports = global.document ?				
			factory( global, true ): //global:window,  noGlobal:true 
			 // 在其余的没有window的环境下,导出一个函数,后期执行函数,如果可以传递一个window进来,也能正常使用,否则报错。
			function( w ) {
				if ( !w.document ) throw new Error( "jQuery requires a window with a document" );
				return factory( w ); //global:window,  noGlobal:undefined
			};
	} else {
		//浏览器或者webview中基于<script>直接导入的
		//  + global:window  noGlobal:undefined
		factory(global);
	};	
})(typeof window !== "undefined" ? window : this,function factory( window, noGlobal){
	// 	直接SCRIPT导入的
    // 	window:window  noGlobal:undefined
    // 	基于WEBPACK中的CommonJS/ES6Module规范导入的JQ
    //	window:window  noGlobal:true
	//...
})

学习到的思想

关于自己写的插件/组件,我们想让自己的代码,既要支持浏览器script直接导入,也要支持commonJS / ES6Module 规范导入。

(function(){
	function jsonp(){};
	if(typeof window !== "undefined"){
		window.jsonp = jsonp;
	};
	if(typeof module ==="object" && typeof module.exports === "object"){
		module.exports = jsonp;
		//导入方式:import jsonp from './jsonp.js';
	}
})()

3. 让插件支持浏览器只导入 、基于webpack处理和AMD模块化处理

//factory 是jQuery闭包中传入函数的实参函数
function factory( window, noGlobal){
	// 	直接SCRIPT导入的
    // 	window:window  noGlobal:undefined
    // 	基于WEBPACK中的CommonJS/ES6Module规范导入的JQ
    //	window:window  noGlobal:true
	"use strict";
	var	version = "3.6.0",	
		jQuery = function( selector, context ) {
			return new jQuery.fn.init( selector, context );
		};
	
	//支持AMD模块化思想,不常用
	if ( typeof define === "function" && define.amd ) {
		define( "jquery", [], function() {
			return jQuery;
		} );
	};
	
	//浏览器直接导入处理
	// $() / jQuery() 都是把内部的jQuery方法执行
	if ( typeof noGlobal === "undefined" ) {
		window.jQuery = window.$ = jQuery;
	};	
	
	// 基于WEBPACK处理
	// module.export = jQuery;
	// 导入方式:import jQuery from 'jQuery';
	return jQuery;
};

4. 解决多库共存的权限冲突

//factory 是jQuery闭包中传入函数的实参函数
function factory( window, noGlobal){
	// 	直接SCRIPT导入的 : window:window  noGlobal:undefined
    // 	基于WEBPACK中的CommonJS/ES6Module规范导入的JQ : window:window  noGlobal:true
	"use strict";
	var	version = "3.6.0",jQuery = function( selector, context ) {return new jQuery.fn.init( selector, context );	};
	
	//多库共存解决权限冲突,导入JQ(代码执行前)解决权限冲突
	var	_jQuery = window.jQuery, /*jQuery冲突*/	_$ = window.$;	/*$冲突*/
	jQuery.noConflict = function( deep ) {
		if ( window.$ === jQuery) { window.$ = _$;	};	
		if ( deep && window.jQuery === jQuery) { window.jQuery = _jQuery;};	return jQuery;
	};
	
	//支持AMD模块化思想,不常用
	if ( typeof define === "function" && define.amd ) {	define( "jquery", [], function() {	return jQuery;	} );};
	
	//浏览器直接导入处理 => $() / jQuery() 都是把内部的jQuery方法执行
	if ( typeof noGlobal === "undefined" ) {window.jQuery = window.$ = jQuery;};	
	
	// 基于WEBPACK处理 module.export = jQuery; 导入方式:import jQuery from 'jQuery';
	return jQuery;
};	

自定义一个jsonp插件

(function(){
	//核心方法
	function jsonp(config){
		config == null ?config = {} :null;
		typeof config !== "object" ? config = {} : null;
		let {
			url,
			params = {},
			configName = "callback",
			success = Function.prototype
		} = config;
		
		// 自己创建一个全局函数
		let f_name = `jsonp${+new Date()}`;
		window[f_name] = function (result){
			typeof succes === "function"? success(result) :null;
			delete window[f_name];
			document.body.removeChild(script);
		};
		
		// 处理url
		params = QS.stringify(params); // QS需要安装 npm install qs 引入
		if(params) url += `${url.includes("?")?"&":"?"}${params}`;
		url += `${url.includes("?")?"&":"?"}${jsonpNam} = ${f_name}`;
		
		// 发送请求
		let script = document.createElement("script");
		script.src = url;
		document.body.appendChild(script);
		
	};
		
	/*多库共存*/
	var	_jsonp = window.jsonp, /*jsonp冲突*/	_$ = window.$;	/*$冲突*/
	jQuery.noConflict = function( deep ) {
		if ( window.$ === jsonp) { window.$ = _$;	};	
		if ( deep && window.jsonp=== jsonp) { window.jsonp= _jsonp;};	return jsonp;
	};
	
	/*暴露API*/
	//浏览器直接导入处理 => $() / jsonp() 都是把内部的jsonp方法执行
	if ( typeof noGlobal === "undefined" ) {window.jsonp= window.$ = jsonp;};
	
	// 基于WEBPACK处理 module.export = jQuery; 导入方式:import jsonp from 'jsonp';
	return jsonp;
})();
// 调用方法jsonp 或者$ 都可以
jsonp({
	url:'https://www.baidu.com/sugrec',
	params:{
		prod:"pc",
		wd:"珠峰"
	},
	jsonpName:'cb',
	success:result =>{
		console.log(result);
	},	
});
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值