标签:
在大型项目开发中,因为项目可读性规范性的需要(就像《编写可维护性的Javascript》一书作者Nicholas Zakas大神所说,他们团队所有成员写出的代码就像是经同一个人之手写出的一样),风格约定要大于个人喜好这一点毋庸置疑,不过什么样才是好的编程风格约定?下面推荐一些实践中沉淀下来的代码规范和最佳实践:
缩进问题和编辑器问题一样是一个因为个人喜好和其他不管值得不值得争执的理由而存在争议的问题,目前存在两个流派,空格流和tab流。个人比较习惯于tab(4个空格距离),在这个问题上团队有协商的余地,不过关键还是两个字:一致。
一行截断成两行后,第2行开头缩进2个tab距离。
// 截断缩进用2个tab
var str = "abcdefghijkl" +
"mnopqrstuvwxyz";
// =截断和上一行=号对齐
var s1 = s2
= s3;
// 块语句的空格规范
if (flag === true) {
alert(‘Yep!‘);
} else {
alert(‘Nop!‘);
}
// 不好的用法:和undefined比较
var cat;
if(cat === undefined) {
doSomething();
}
尽管上面的代码能够正常运行,但是好的方式是下面这种:
// 好的用法,初始化为null
var cat = null;
if(cat === null) {
doSomething();
}
这里不存在如上所述undefined的多种可能的混淆情形。
分清楚typeof和instanceof的适用情形
in的妙用:
// 判断对象类型是否为数组
function isArray(val){
if(typeof Array.isArray === ‘function‘){
return Array.isArray(val);
} else {
return Object.prototype.toString.call(val) === ‘[object Array]‘;
}
}
hasOwnProperty是Object唯一不会遍历原型链的方法
// obj为一般对象
if (obj.hasOwnProperty(‘prop‘)) {
;// ...
}
// obj为DOM对象
if(‘hasOwnProperty‘ in obj && obj.hasOwnProperty()) {
;// ...
}
到目前为止javascript没有引入块语句作用域,所以有些块语句里声明的变量可能会带来语义上的混淆。因此好的实践是将函数作用域或者对象作用域内所有声明的变量按照隐式变量提升的方式显式放到代码的开头部分。
// 所有局部变量合成为一个var声明语句
var s1, s2, s3,
str1 = ‘abcde‘,
obj = { 1:‘abc‘, ‘xx‘:‘oo‘ };
给变量用内置类型的字面量赋值以后,每次使用这个变量会产生一个临时包装对象,但是这个包装对象是每次用后即弃的。
// 临时包装对象用后即弃
var str = "abc";
str.flag = true;
console.log(str.flag); // undefined
上面代码给str添加了一个flag属性并赋值为true,但是这个str临时包装对象赋完值立即弃掉了。因此下一句打印是打印不出这个属性的值的。如果使用new操作符来显式创建这个对象,结果还是一样的:
// 不好的写法:显式new一个内置类型包装对象
var str = new String("abc");
str.flag = true;
console.log(str.flag); // undefined
上面的代码可能对开发者产生疑惑,因为第一句貌似是给str赋值了一个String对象。因此,为了避免不必要的代码歧义,建议不要使用new来创建内置类型对象。
前端代码应该尽量避免html/css/javascript代码之间的依赖性,提高各自的独立性。
/* css里使用express表达式严重降低性能 */
.box {
width: expression(document.body.offsetWidth + ‘px‘);
}
// 全兼容的事件绑定函数
function addListener(target, type, handler) {
if (target.addEventListener) {
target.addEventListener(type, handler, false);
} else if (target.attachEvent) { // IE
target.attachEvent(‘on‘ + type, handler);
} else {
target[‘on‘ + type] = handler;
}
}
不要去破坏别人的模块。这里推荐一个无破坏性的命名空间定义方式:
// 无破坏性的命名空间定义方式
var yourGlobal = {
namespace: function(ns) {
var parts = ns.split(‘.‘),
object = this,
i, len;
for (i = 0, len = parts.length; i < len; i++) {
if (!object[parts[i]]) {
object[parts[i]] = {};
}
object = object[parts[i]];
}
return object;
}
}
下面的代码直接将处理放到了handle函数里,如果在没有点击的情况下想要调用它就麻烦了:
// 不好的写法
function handleClick(event) {
console.log(event.clientX, event.clientY);
}
将应用逻辑分离后的代码:
// 应用逻辑和事件处理隔离
function handleClick(event) {
logPosition(event);
}
function logPosition(event) {
console.log(event.clientX, event.clientY);
}
不要分发事件对象
上面的代码处理还是有问题,因为logPosition的参数带有应用逻辑不需要的信息,因此继续改进:
// 改进:避免分发事件对象
function handleClick(event) {
logPosition(event.clientX, event.clientY);
}
function logPosition(x, y) {
console.log(x, y);
}
对象的保护:Object的方法preventExtension、seal和freeze(保护强度递增)
// 对象的保护
‘use strict‘
// 不能增加属性
Object.preventExtension(cat);
console.log(Object.isExtensible(cat));
cat.age = 1; // error.
// 不能增删属性
Object.seal(cat);
console.log(Object.isExtensible(cat));
console.log(Object.isSealed(cat));
delete cat.name; // error.
cat.age = 1; // error.
// 不能增删改
Object.freeze(cat);
console.log(Object.isExtensible(cat));
console.log(Object.isSealed(cat));
console.log(Object.isFrozen(cat));
cat.name = "Kitty"; // error.
delete cat.name; // error.
cat.age = 1; // error.
注意:以上error如果不使用strict模式的话会被浏览器默默吞掉。
常用文件结构:
原文地址:http://www.mrraindrop.com/2013/07/13/maintainable-javascript-notes/
标签:
原文地址:http://www.cnblogs.com/walter371/p/5197581.html