模块化/单例设计模式
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',"白静","汪林"];
})()
// 真实业务开发
// A
let 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:query
query,
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下是global
var 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;
}
})()