Mastering the Module Pattern(2014) 阅读笔记

模块模式可以帮助开发者更好地组织代码, 在代码中不再过度使用thisprototype.

创建模块

1
2
3
(function () {
// code
})();

使用IIFE创建新的作用域, JS本身不存在”私有”的概念, 用IIFE可以模拟”私有”, 包围所有的业务逻辑, 只返回所需的部分, 避免其他部分暴露在全局作用域.

1
2
3
var Module = (function () {
// code
})();

对所创建的模块进行命名, 可以在任何时候调用, 也能将其传到另一个模块.

私有方法

可以在模块内部创建私有方法:

1
2
3
4
5
6
7
var Module = (function () {

var privateMethod = function () {
// do something
};

})();

“return”

如果想在模块内部定义可供外部使用的公有方法, 可以将方法以对象字面量的形式return, 这样在所创建的模块的命名空间中就存在该方法, 例:

1
2
3
4
5
6
7
8
9
var Module = (function () {

return {
publicMethod: function () {
// code
}
};

})();

以这样的形式调用:

1
Module.publicMethod();

返回匿名对象字面量

最简单的模式就是以上所提及的模式, 在模块中返回匿名对象字面量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var Module = (function () {

var privateMethod = function () {};

return {
publicMethodOne: function () {
// 此处可以调用 privateMethod()
},
publicMethodTwo: function () {

},
publicMethodThree: function () {

}
};

})();

Locally scoped Object Literal

1
2
3
4
5
6
7
8
9
10
11
12
13
var Module = (function () {

var myObject = {}; // 私有对象字面量

var privateMethod = function () {}; // 私有方法

myObject.someMethod = function () {
// 暴露在外部的方法
};

return myObject;

})();

最后一行返回了myObject, 我们定义的模块Module并不在意私有对象字面量是否匿名, 因此对其命名是个好方法, 在最后一行返回, 可以更好地组织代码.

Stacked locally scoped Object Literal

和前一个示例很像, 不过使用了”传统”的对象字面量声明形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var Module = (function () {

var privateMethod = function () {};

var myObject = {
someMethod: function () {

},
anotherMethod: function () {

}
};

return myObject;

})();

locally scoped Object Literal 在使用函数之前先定义该函数以避免变量提升(因为function myFunction () {}会遇到变量提升的问题). 使用var myFunction = function () {}'语法就不用在意这个问题, 因为我们必须在使用前定义, 同时这个方法也使调试变得更容易, JS解释器会根据我们在代码中定义的顺序渲染各行代码. “stacked”对象字面量的方法还会降低代码可读性, 使其看起来十分冗余. and there is no obvious locally scoped Object namespace for me to bolt public methods onto.

暴露式模块模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var Module = (function () {

var privateMethod = function () {
// private
};

var someMethod = function () {
// public
};

var anotherMethod = function () {
// public
};

return {
someMethod: someMethod,
anotherMethod: anotherMethod
};

})();

调用”私有”方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var Module = (function () {

var privateMethod = function (message) {
console.log(message);
};

var publicMethod = function (text) {
privateMethod(text);
};

return {
publicMethod: publicMethod
};

})();

// Example of passing data into a private method
// the private method will then `console.log()` 'Hello!'
Module.publicMethod('Hello!');

不仅限于私有方法, 私有数组和私有对象也可使用这样的方法获取:

1
2
3
4
5
6
7
8
9
10
11
12
13
var Module = (function () {

var privateArray = [];

var publicMethod = function (somethingOfInterest) {
privateArray.push(somethingOfInterest);
};

return {
publicMethod: publicMethod
};

})();

添加模块

利用实现扩展模块: 下例中ModuleTwo为Module的扩展模块, 添加了extension方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var Module = (function () {

var privateMethod = function () {
// private
};

var someMethod = function () {
// public
};

var anotherMethod = function () {
// public
};


return {
someMethod: someMethod,
anotherMethod: anotherMethod,
};

})();
1
2
3
4
5
6
7
8
9
10
var ModuleTwo = (function (Module) {

Module.extension = function () {

};

return Module;

})(Module || {});
// Module || {} 防止Module为undefined

私有方法命名惯例

下划线_以标示私有方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var Module = (function () {

var _privateMethod = function () {
// private stuff
};

var publicMethod = function () {
_privateMethod();
};

return {
publicMethod: publicMethod
};

})();