模块化可以使你的代码低耦合,功能模块直接不相互影响。
模仿块级作用域
JS中没有块级作用域,而是函数作用域,函数中声明的变量和函数不会泄露到外部作用域。那么就可以通过在函数中创建私有变量。
function f() {
var a = 1;
}
a // ReferenceError: a is not defined
但是这样函数名也是一个全局变量,也有污染全局变量的危险。那么如果使用匿名函数呢?
// 这样会报错,函数声明必须要有标识符
function () {
var a = 1;
}
// 仍是会生成全局标识符
var f = function () {
var a = 1;
}
JS中可以利用立即执行函数模仿块级作用域,立即函数是一个函数表达式而不是函数声明,不会提升,解析到这行就会立即运行。这样既不会污染全局变量,函数也可以执行。
// 写法一
(function () {
// 块级作用域
}());
// 写法二
(function () {
// 块级作用域
})();
// 写法三
(function (fn) {
fn();
})(function f() {
// 块级作用域
});
私有变量
JS中函数的参数、局部变量和函数内部定义的函数都不能再函数的外部被访问,所以被称为私有变量。
那么有权访问私有变量和私有函数的公有方法称为特权方法。
特权方法是在对象上创建,一般有两种方式:构造函数定义特权方法和静态私有变量实现特权方法。这两种都是用于为自定义类型创建私有变量和特权方法的。
构造函数定义特权方法;
function F() { var a = 1; // 私有变量 function sayA() { // 私有函数 console.log(a); } this.sayA = sayA; // 特权方法 } var f = new F(); f.sayA(); // 1
缺点是每个实例都会创建一组新方法,违反了构造函数与实例对象相分离的原则。并且,非常耗费内存。
静态私有变量实现特权方法;
(function () { var a = 1; // 私有变量 function sayA() { // 私有函数 console.log(a); } // 构造函数使用函数表达式,且不使用var,函数声明只能创建局部变量,不使用var的函数表达式可以创建全局变量,让其在私有作用域之外访问 F = function () { // }; F.prototype.sayA = sayA; // 特权方法 })(); var f = new F(); f.sayA(); // 1
缺点是私有变量是公用的,所有实例使用的都是相同的私有变量。
模块模式
模块模式是为单例创建私有变量和特权方法。
在JS可以利用立即执行函数和闭包创建模块。
模块模式需要具备两个必要条件:
- 必须有外部的封闭函数, 该函数必须至少被调用一次( 每次调用都会创建一个新的模块实例);
封闭函数必须返回至少一个内部函数, 这样内部函数才能在私有作用域中形成闭包, 并且可以访问或者修改私有的状态;
var f = function () {
var a = 1; // 私有变量 return { // 函数调用后返回一个包含公开属性和方法的对象 sayA: function () { // 特权方法,通过闭包可以在外部调用时访问内部私有变量 console.log(a); } }
};
f().sayA(); // 1
利用匿名函数自执行改写
var f = (function () {
var a = 1; // 私有变量
return { // 函数调用后返回一个包含公开属性和方法的对象
sayA: function () { // 特权方法,通过闭包可以在外部调用时访问内部私有变量
console.log(a);
}
}
})();
f.sayA(); // 1