闭包的进阶思想 & JQ源码环境判断

135 阅读2分钟

闭包的进阶思想 & JQ源码环境判断

单例设计模式 & 模块化编程思想

模块化编程历史[当代前端开发,都是模块化编程:公用性&复用性,提高开发效率,方便团队挂历,团队协作开发...]

+ @1 高级单例设计模式[闭包 + 对象] 问题模块之间的依赖,需要明确导入顺寻
+ @2 AMD  按需加载(require.js) 问题:所有的依赖都需要提前导入  "前置依赖"
+ @3 CMD(sea.js) & CommonJS规范(Node.js)  问题: 客户端不支持CommonJS规范(如果导入sea.js是可以支持的)  当代打包工具webpack是支持CommonJs规范的,最后按照CommonJS把各个模块进行打包,编译为浏览器可以支持的代码[webpack本身是基于node环境进行的,基于webpack打包后的代码,是webpack自己实现了一套CMD规范]
+ @4 ES6Module模板规范    特点:webpack中也支持浏览器中也支持 **(html引入js加上type='module')**

扩充:JS代码可以在哪运行

* + 浏览器端 webkit(blink)、gecko、trident...

* + webview「手机端APP中」 webkit

* 「有window,不支持CommonJS规范,支持ES6Module规范」

* -----

* + node环境「没有window、支持CommonJS规范、但是不支持ES6Module规范」

* -----

* + 可以基于webpack进行编译「支持window、也支持CommonJS规范、支持ES6Module规范(可以让ES6Module和CommonJS混合调用)...」:基于node环境进行打包处理,打包后的结果交给浏览器端去渲染和运行

单例模式

/*
	立即执行函数 + 对象
*/

// 新闻板块
let newsModule = (function () {
    let time = new Date();
    const query = function query() {
        // ...
    };
    const handle = function handle() {
        // ...
    };

    // 把供其它板块调用的方法,暴露到全局对象上「局限:暴露的内容比较多,则还会引发全局变量冲突」
    // window.query = query;

    return {
        // query:query
        query,
        handle
    };
})();

// 皮肤板块
let skinModule = (function () {
    let time = '2021-05-03';
    const handle = function handle() {
        // ...
    };
    newsModule.query();

    return {
        handle
    };
})();

JQ源码环境判断 & 冲突解决

/*
	1.typeof module 和 typeof module.exports 判断一下是否支持CommonJS规范=>要么是Node环境或者webpack环境
	2.module.exports 基于CommonJS规范的抛出 
	3.global.document? XXX : XXX 三目运算符 只有global === window才又document 所以一定是再webpack环境下
	
*/
if ( typeof module === "object" && typeof module.exports === "object" ) {
    module.exports = global.document ?
        factory( global, true ) :
    	//4.不是webpack环境就是Node环境  Node环境一定会报错
        function( w ) {
            if ( !w.document ) {
                throw new Error( "jQuery requires a window with a document" );
            }
            return factory( w );
        };
} else {
    factory( global );
}

/*window环境直接挂载window*/
if ( typeof noGlobal === "undefined" ) {
	window.jQuery = window.$ = jQuery;
}

/*可以使用AMD规范*/
if ( typeof define === "function" && define.amd ) {
	define( "jquery", [], function() {
		return jQuery;
	} );
}

/*
	解决冲突
		1.记录下之前挂载window的jQuery/$ 存在_jQuery/_$
		2.在jQuery上添加个noConflict方法 如果window.$ === jQuery 如果window.$挂的是自己的jQuery就把_jQuery挂到window,把位置让给别人
		3.return jQuery;抛出自己作为函数回调
		4.let my$  = jQuery.noConflict();接受
*/
var	_jQuery = window.jQuery,
	_$ = window.$;
jQuery.noConflict = function( deep ) {
	if ( window.$ === jQuery ) {
		window.$ = _$;
	}
    
	if ( deep && window.jQuery === jQuery ) {
		window.jQuery = _jQuery;
	}

	return jQuery;
};
自己封装兼容浏览器端/Node/webpack/webview
/*
	1.一般不做ES6module环境适配
	2.判断有有window 如果有就挂载window
	3.如果是CommonJS规范就 按照commonJS规范抛出
*/
const func1 = function (){
    console.log("可以调用");
}

const func2 = function (){
    console.log("可以调用1");
}

//判断有有window 如果有就挂载window
if(typeof window !== 'undefined' ){
    window.func = window.$ = {func1,func2};
}

//如果是CommonJS规范就 按照commonJS规范抛出
if(typeof module === 'object' && typeof module.exports === 'object'){
    module.exports = {
        func1,
        func2
    }
}
自己手写解决冲突代码
const func1 = function (){
    console.log("可以调用");
}

const func2 = function (){
    console.log("可以调用1");
}

//解决冲突
const noconflict = function (){
    //我现在想在window挂载$ 但是我害怕冲突 所以我把之前的window.$保存下来
    let _$ = window.$;
    if(window.$ === func){
        window.$ = _$
    }
    // 把位置让出去后 把自己的方法返回  在外部就可以 let myfunc = noconflict()
    return func;
}

let func = {
    func1,
    func2,
    noconflict
}

if(typeof window !== 'undefined' ){
    window.func = window.$ = func;
}

if(typeof module === 'object' && typeof module.exports === 'object'){
    module.exports = func
}