《JavaScript 面向对象编程指南》笔记

1. 行为隔离

内容(HTML),外观(CSS),行为(JavaScript)

1.1 内容

  • 避免在HTML标签中使用 style 属性
  • 不要使用与外观有关的 HTML 标签,例如<font>
  • 尽量根据语义需要来选择标签

1.2 外观

要将外观与内容分开

1.3 行为

  • 尽可能少用<script>标签
  • 尽量不要使用内嵌事件的处理方法
  • 尽量不要使用 CSS 表达式
  • 当 JavaScript 被用户禁用时,我们要动态地添加一些表示无目标的替换标记
  • 在内容末尾、<body>标签之前,插入一个 external.js 文件

2. 命名空间

只定义一个全局变量,并将其他变量和方法定义为该变量的属性。

2.1 将对象用做命名空间

1
2
3
4
5
6
7
8
9
10
11
12
var MYAPP = MYAPP || {};
MYAPP.event = {
addListener: function(el, type, fn) {
// ...
},
removeListener: function(el, type, fn) {
// ...
},
getEvent: function(e) {
// ...
}
};

2.2 命名空间中的构造器应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14

MYAPP.dom = {};
MYAPP.dom.Element = function (type, properties)
{
var tmp = document.createElement(type);
for(var i in properties)
{
if(properties.hasOwnProperty(i))
{
tmp.setAttribute(i, properties[i]);
}
}
return tmp;
}

2.3 namespace()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var MYAPP = {};
MYAPP.namespace = function(name)
{
var parts = name.split('.');
var current = MYAPP;
for(var i = 0; i < parts.length; ++i)
{
if(!current[parts[i]])
{
current[parts[i]] = {};
}
current = current[parts[i]];
}
}
1
2
3
4
5
6
7
8
9
10
MYAPP.namespace('event');
MYAPP.namespace('dom.style');

// 等价于
var MYAPP = {
event: {},
dom: {
style: {}
}
}

3. 初始化分支

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var MYAPP = MYAPP || {};
MYAPP.event = {
addListener: null,
removeListener: null
};

if(window.addEventListener) {
// for popular browsers
MYAPP.event.addListener = function(el, type, fn) {
el.addEventListener(type, fn, false);
};
MYAPP.event.removeListener = function(el, type, fn) {
el.removeEventListener(type, fn, false);
};
}
else if(document.attachEvent) {
// for IE
MYAPP.event.addListener = function(el, type, fn) {
el.attachEvent('on' + type, fn);
};
MYAPP.event.removeListener = function(el, type, fn) {
el.detachEvent('on' + type, fn);
};
}
else {
// older browsers
MYAPP.event.addListener = function(el, type, fn) {
el['on' + type] = fn;
};
MYAPP.event.removeListener = function(el, type, fn) {
el['on' + type] = null;
};
}

4. 惰性初始

在相关函数第一次被调用时才会发生。

5. 配置对象

1
MYAPP.com.FancyButton('dude', {color: 'red', height: 10})

类似上面的形式,与函数多个参数初始化相比,灵活了一些;但个人觉得,这样少了约束,基于接口调用者不可信任的原则,在其他编程语言中,我不会这么用。

6. 私有属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var MYAPP = {};
MYAPP.dom = {};
MYAPP.dom.FancyButton = function(text, conf) {
var styles = {
font: 'Verdana',
border: '1px solid black',
color: 'black',
background: 'grey'
};
function setStyles(b) {
for(var i in styles) {
if(styles.hasOwnProperty(i)) {
b.style[i] = conf[i] || styles[i];
}
}
}
conf = conf || {};
var b = document.createElement('input');
b.type = conf.type || 'submit';
b.value = text;
setStyles(b);
return b;
}

7. 特权函数

提供一些公共函数,使其可以访问对象的私有方法和属性。

8. 私有函数的公有化

1
2
3
4
5
6
7
8
9
10
11
12
13
var MYAPP = {};
MYAPP.dom = (function() {
var _setStyle = function(el, prop, value) {
console.log('setStyle');
};
var _getStyle = function(el, prop) {
console.log('getStyle');
};
return {
setStyle: _setStyle,
getStyle: _getStyle
}
}());

9. 即时函数

保证全局命名空间不被污染。

1
2
3
(function() {
// do something
}();

10. 链式调用

使用 set方法时,return this 即可。

1
2
3
4
var obj = new MYAPP.dom.Element('span');
obj.setText('hello')
.setStyle('color', 'red')
.setStyle('font', 'Verdana');

11. JSON

1
2
JSON.parse(RAW_DATA);
JSON.stringify(JSON_DATA);