模块化/单例设计模式
let name = 'Erina';let age = 21;let sex = '女‘;let friends = ["秋含","白静","汪林"];let name = 'qiuhan';let age = 20;let sex = '男';let friends = ['erina',"白静","汪林"];

这样会重复定义,会报错,在没有对像和函数的情况下,经常会出现“全局变量污染”的现象。
方案一:对象
分组的作用,把描述同一个事物的属性和方法都放在相同的空间(堆内存)中
let person1 = {name: 'Erina',age: '21'}let person2 = {name: 'Qiuhan',age: '20'}
方案二:闭包/私有上下文
保护作用,保护私有变量和全局变量不产生冲突,方式全局变量污染。
(function(){let name = 'Erina';let age = 21;let sex = '女‘;let friends = ["秋含","白静","汪林"];(function(){let name = 'qiuhan';let age = 20;let sex = '男';let friends = ['erina',"白静","汪林"];})()
// 真实业务开发// Alet AModule = (function () {let step = 0;function fn() {}function query() {}// 我们想把私有的东西暴露出去共外面调用(API),供B调用// 1. window.xxx=xxx 瑕疵:不能给全局下暴露太多的方法,否则又出现“全局变量污染”// window.query = query; 在B那边直接调用query()// 2. 基于返回对象(分组)的方法,把需要暴露的API,都放置到同一个空间下// AModule等于自执行函数执行的返回的结果->对象// 如果需要把一些私有的属性方法和私有变量暴露到外面使用,通过return一个对象的方式,把对象赋值给AModule// 一个私有上下文下,它里面的某一个堆,这个堆地址被当前上下文以外的全局的AModule占用,这个私有上下文就不会// 被释放,形成了一个闭包。// AModule的方式就是单例设计模式return {// query:queryquery,step};})();// B(function () {let step = 0;function fn() {}// query(); // window.query();AModule.query();})();
终极处理方案:单例设计模式(最早的模块化编程方式)
- 原理:利用闭包的保护及对象的分组特征,结合在一起实现的
- 工具库:大量公共的方法(有些方法是内部用的,有些是可以供外面调用的)
- 单例:单独的实例,每一个实例都是独立开来的,里面有很多自己的私有属性和方法
utils和SearchModule返回的都是对象(单独的空间,单独的实例),每一个对象都是Object的单独实例。let utils = {};let SearchModule = {};
- 每一个对象都是Object的单独实例
let obj={};字面量方式let obj=new Object();构造函数方式
- 命名空间:俗称“对象名”(utils也叫命名空间)
- 分组特征 (想用明命空间就是想用分组特征)
utils 和 SearchModule 返回的都是对象,只不过还利用了闭包形成了私有的闭包,让部分属性方法私有,让部分属性方法公有。
let utils = (function () {function getCss() {}function setCss() {}function css() {getCss();setCss();}return {css};})();// 搜索模块let SearchModule = (function () {let keyword = "";function handle() {}function query() {}utils.css();return {handle,// init:function(){}init() {// 控制业务板块中我们先执行谁,再执行谁:控制业务逻辑处理顺序的 “命令模式”query();handle();}};})();SearchModule.init();// 资讯模块let NewsModule = (function () {let data = [];function query() {}utils.css();SearchModule.handle();return {init() {}};})();NewsModule.init();
PS:构造函数模式 let p = new Person() ,不是单例模式。
JQuery源码分析
(function (global, factory) {// ...})(typeof window !== "undefined" ? window : this, function (window, noGlobal){});
var A = typeof window !== "undefined" ? window : this;// 利用暂时性死区:一个未被声明的变量在typeof检测的时候不会报错,只是返回"undefined"// ->检测window是否存在// JS在浏览器中执行:是存在window的(window === GO)// JS在NODE中执行:不存在window,全局对象是global// ->A最后的结果根据执行所在的环境不一样,结果也不一样:浏览器下是window,node下是globalvar B = function (window, noGlobal){// 如果是在浏览器环境中执行的JS代码:// window: window// noGlobal: undefined(没有传值)// 如果是在NODE环境下执行// window: global// noGlobal: true"use strict";var jQuery = function (selector, context) {};if(typeof noGlobal === "undefined") {// 浏览器环境下:暴露给全局的俩个变量(值都是私有的jQuery)// jQuery// $window.jQuery = window.$ = jQuery;// $() = jQuery()}return jQuery;};"use strict";// global: window / global// factory: B(function (global, factory) {// 验证是否支持CommonJS/ES6Module规范(支持这个规范的是Node.js)if ( typeof module === "object" && typeof module.exports === "object" ) {// For CommonJS and CommonJS-like environments where a proper `window`// is present, execute the factory and get jQuery.// For environments that do not have a `window` with a `document`// (such as Node.js), expose a factory as module.exports.// This accentuates the need for the creation of a real `window`.// e.g. var jQuery = require("jquery")(window);// See ticket #14549 for more info.// 代码是运行在node环境下的(或者是基于webpack打包运行的项目)module.exports = global.document ?factory( global, true ) :function( w ) {if ( !w.document ) {throw new Error( "jQuery requires a window with a document" );}return factory( w );};} else {// 运行在浏览器或者webview(相当于浏览器)中// =>B(window)factory( global );}})(A, B);
应用
在我们自己编写类库/插件/UI组件/框架的时候,为了防止全局变量污染,我们需要基于闭包的机制进行”私有化“处理。
封装一个轮播路banner插件
(function(){function Banner(){}window.Banner = Banner;})()
- 能够在浏览器中运行
- 能支持CommonJS或者ES6Module规范(node/webpack)
(function(){function Banner(){}// 浏览器环境if(window!==undefined) {window.Banner = Banner;}// 支持CommonJS或者ES6Module//if(typeof module !== "undefined" && typeof module.exports !== "undefined") {if ( typeof module === "object" && typeof module.exports === "object" ) {module.exports = Banner;}})()
