1、前端开发规范
WEB客户端开发自成体系, 主要用于智能终端(iPhone、Android手机、iPad、Android Pad)和传统PC的开发。JS规范、HTML规范和CSS规范对客户端开发进行全方位指导,统一编码规范、提高可读性、降低维护成本。
1.1一般规范
应用在 HTML, JavaScript 和 CSS上的通用规则。
1.1.1文件/资源命名
1) 以可读性而言,减号(-)用来分隔文件名;
2) 使用驼峰方式命名文件名与文件所在的文件夹,便于统一配置;
3) 确保文件命名总是以字母开头而不是数字;
4) 特殊含义的文件,需要对文件增加前后缀或特定的扩展名(比如 .min.js, .min.css),抑或一串前缀(比如 all.main.min.css)。使用点分隔符来区分这些在文件名中带有清晰意义的元数据。
1.1.1.2 文本缩进
一次缩进4个空格
1.1.1.3 代码检查
对于前端JavaScript这种比较宽松自由的编程语言来说,严格遵循编码规范和格式化风格指南极为重要。前端开发人员需严格遵循开发规范,并且使用自动代码检查工具(如JSHint)降低语法错误,确保代码正确执行。
JSHint是一款检查JS代码规范与否的工具,用来检查JS代码的规范性。它提供了配置的方法,来检查不符合开发规范的错误。
1.1.2 HTML开发规范
1.1.2.1 文档类型
使用 HTML5的文档类型申明: <!DOCTYPE html>。
1.1.2.2 脚本加载
出于性能考虑,脚本应该异步加载。不允许将脚本放置在 <head> 内,比如 <scriptsrc="main.js"></script>,其加载会一直阻塞 DOM解析,直至它完全地加载和执行完毕。这会造成页面显示的延迟,特别是一些重量级的脚本,不利于提高用户体验度。
异步加载脚本可缓解这种性能影响,有如下几种解决方案。
1、如果只需兼容 IE10+,可将 HTML5 的async 属性加至脚本中,它可防止阻塞 DOM 的解析,也可以将脚本引用写在 <head> 里也没有影响。
2、如需兼容老旧的浏览器,实践表明可使用用来动态注入脚本的脚本加载器。可以考虑 yepnope 或 labjs。注入脚本的一个问题是:一直要等到 CSS 对象文档已就绪,它们才开始加载(短暂地在 CSS 加载完毕之后),这就对需要及时触发的 JS 造成了一定的延迟,也影响了用户体验。
终上所述,兼容老旧浏览器(IE9-)时,应该遵循以下最佳实践。
脚本引用写在body 结束标签之前,并带上 async 属性。这虽然在老旧浏览器中不会异步加载脚本,但它只阻塞了 body 结束标签之前的 DOM 解析,这就大大降低了其阻塞影响。而在现代浏览器中,脚本将在 DOM 解析器发现 body 尾部的script 标签才进行加载,此时加载属于异步加载,不会阻塞 CSSOM(但其执行仍发生在 CSSOM 之后)。
在所有浏览器中,推荐
在现代浏览器中,推荐
1.1.2.3 语义化
根据元素(有时称作“标签”)其被创造出来时的初始意义来使用它。打个比方,用 heading 元素来定义头部标题,p 元素来定义文字段落,用 a 元素来定义链接锚点。
有根据有目的地使用 HTML 元素,对于可访问性、代码重用、代码效率来说意义重大。
以下示例列出了一些的语义化 HTML 主要情况:
不推荐
推荐
1.1.2.4 多媒体回溯
对页面上的媒体而言,像图片、视频、canvas 动画等,要确保其有可替代的接入接口。图片文件我们可采用有意义的备选文本(alt),视频和音频文件我们可以为其加上说明文字或字幕。
提供可替代内容,提高可用性。图片的 alt 属性可不填写内容,纯装饰性的图片可以使用alt=""。
不推荐
推荐
尽量用 alt 标签去描述图片。
不推荐
推荐
1.1.2.5 关注点分离
web 中的关注点包括信息(HTML 结构)、外观(CSS)和行为(JavaScript)。为了使它们成为可维护的干净整洁的代码,必须将它们分离开。严格地保证结构、表现、行为三者分离,并使三者之间没有太多的交互和联系。
就是说,尽量在文档和模板中只包含结构性的 HTML;而将所有表现代码,移入样式表中;将所有动作行为,移入脚本中。
在此之外,为使得它们之间的联系尽可能的小,在文档和模板中也尽量少地引入样式和脚本文件。
清晰的分层意味着:
1) 合并样式,不引用过多样式表
2) 合并脚本,不使用过多脚本
3) 不使用行内样式(<style>.no-good{}</style>)
4) 不在元素上使用style 属性(<hr style="border-top: 5px solidblack">)
5) 不使用行内脚本(<script>alert(‘nogood’)</script>)
6) 不使用表象元素(<b>, <u>, <center>, <font>, <b>)
7) 不使用表象 class 名(red, left, center)
不推荐
推荐
1.1.2.6 Type属性
省略样式表与脚本上的 type 属性。鉴于 HTML5 中以上两者默认的 type 值就是 text/css 和text/javascript,所以 type 属性一般是可以忽略掉的。在老旧版本的浏览器中这么做也是安全可靠的。
不推荐
推荐
1.1.2.7 ID和锚点
在利用锚点提高用户体验方面,一个比较好的做法是将页面内所有的头部标题元素都加上 ID。页面 URL 的 hash 中带上对应的 ID 名称,即形成描点,方便跳转至对应元素所处位置。
例如,在浏览器中输入URL(带有锚点)时,浏览器将定位至锚点对应元素位置。
1.1.2.8 格式化规则
在每一个块状元素,列表元素和表格元素后,对其子孙元素进行缩进。内联元素写在一行内,块状元素还有列表和表格要另起一行。
推荐
1.1.2.9 HTML引号
使用双引号(“”)而不是单引号(‘’)
不推荐
推荐
1.1.3 CSS开发规范
1.1.3.1 ID andclass 命名
ID和class(类)名使用可以反应元素目的和用途的名称,或其他通用名称。使用具体且反映元素目的的名称,这些是最容易理解的,而且发生变化的可能性最小。
通用名称只是多个元素的备用名,他们兄弟元素之间是一样的,没有特别意义。
ID命名要注意明确性及唯一性;class命名要注意通用性及复用性。
1.1.3.2 合理的避免使用ID
ID不应该被应用于样式。因为ID的样式不能被复用并且每个页面中你只能使用一次ID。只有为了确定网页或整个站点中的唯一有效位置时才使用ID。
不推荐
推荐
1.1.3.3 CSS选择器中避免标签名
当构建选择器时应该使用清晰, 准确和有语义的class(类)名。不要使用标签选择器。使用class(类)名,而不是代码元素,这样会更容易维护。从分离的角度考虑,在表现层中不应该分配html标记/语义。
不推荐
推荐
1.1.3.4 尽可能的精确
很多前端开发人员写选择器链的时候不使用直接子选择器,导致疼痛的设计问题并且有时候可能会很耗性能。
如果不是需要匹配到DOM末端的选择器, 应该使用直接子选择器。
考虑下面的DOM:
下面的CSS应用于有title类的全部三个元素。赋予content类下的title类 和 teaser类下的title类下不同的样式,需要精确的选择器编写他们的样式。
不推荐
推荐
1.1.3.5 缩写属性
CSS提供了各种缩写属性(如 font 字体)应该尽可能使用,即使在只设置一个值的情况下。使用缩写属性对于代码效率和可读性是有很有用的。
不推荐
推荐
1.1.3.6 0和单位
省略“0”值后面的单位。不要在0值后面使用单位,除非有值。
不推荐
推荐
1.1.3.7 十六进制表示法
在可能的情况下,使用3个字符的十六进制表示法。
例如,颜色值允许这样表示,3个字符的小写的十六进制表示法更简短。
不推荐
推荐
1.1.3.8 ID 和 Class(类) 名的分隔符
使用连字符(中划线)分隔ID和Class(类)名中的单词。为了增强课理解性,在选择器中不要使用除了连字符(中划线)以为的任何字符(包括没有)来连接单词和缩写。
另外,作为该标准,预设属性选择器能识别连字符(中划线)作为单词[attribute|=value]的分隔符。
不推荐
推荐
1.1.3.9 声明顺序
为了保证更好的可读性和可扫描性,样式声明应该遵循以下顺序:
1) 结构性属性:
a) display
b) position, left, top, right 等.
c) overflow, float, clear 等.
d) margin, padding
2) 表现性属性:
a) background, border 等.
b) font, text
不推荐
推荐
1.1.3.10 声明结束
为了保证一致性和可扩展性,每个声明应该用分号“;”结束,每个声明换行。
不推荐
推荐
1.1.3.11 属性名结束
出于一致性的原因,属性名的冒号后使用一个空格,属性和值(但属性和冒号之间没有空格)的之间使用一个空格。
不推荐
推荐
1.1.3.12 CSS引用
属性选择器或属性值用双引号(“”),而不是单引号(“)括起来。
URI值(url())不要使用引号。
不推荐
推荐
1.1.4 JS开发规范
1.1.4.1严格模式
ECMAScript 5 严格模式(‘usestrict’)可在整个脚本或独个方法内被激活。严格模式对应不同的javascript 语境会做更加严格的错误检查。严格模式也确保了 javascript 代码更加的健壮,运行的也更加快速。
严格模式会阻止使用在未来很可能被引入的预留关键字。
你应该在你的脚本中启用严格模式,最好是在独立的 IIFE 中应用它。避免在你的脚本第一行使用它而导致你的所有脚本都启动了严格模式,这有可能会引发一些第三方类库的问题。
不推荐
推荐
1.1.4.2 明智地使用真假判断
在一个 if 条件语句中使用变量或表达式时,会做真假判断。if(a == true) 是不同于 if(a) 的。后者的判断比较特殊,我们称其为真假判断。这种判断会通过特殊的操作将其转换为 true 或 false,下列表达式统统返回 false:
false, 0, undefined, null, NaN, \'\'(空字符串)。
以下示例展示了真假判断是如何工作的:
1.1.4.3 类型
1) 原始值: 相当于传值(包括string、number、boolean、null、undefined)
|
var foo = 1, bar = foo; bar = 9; console.log(foo, bar); // => 1, 9 |
2) 复杂类型: 相当于传引(包括object、array、function)
|
var foo = [1, 2], bar = foo;
bar[0] = 9; console.log(foo[0], bar[0]); // => 9, 9 |
1.1.4.4 对象
1) 使用字面值创建对象
|
// bad var item = new Object();
// good var item = {}; |
2) 不要使用保留字 reservedwords作为键
|
// bad var superman = { class: \'superhero\', default: { clark: \'kent\' }, private: true };
// good var superman = { klass: \'superhero\', defaults: { clark: \'kent\' }, hidden: true }; |
1.1.4.5 数组
1) 使用字面值创建数组
// bad
var items = new Array();
// good
var items = [];
2) 如果你不知道数组的长度,使用push
var someStack = [];
// bad
someStack[someStack.length] = \'abracadabra\';
// good
someStack.push(\'abracadabra\');
3) 当你需要拷贝数组时使用slice
var len =items.length,
itemsCopy = [],
i;
// bad
for (i =0; i < len; i++) {
itemsCopy[i] = items[i];
}
// good
itemsCopy= items.slice();
4) 使用slice将类数组的对象转成数组.
function trigger() {
var args = Array.prototype.slice.call(arguments);
...
}
1.1.4.6 字符串
1) 对字符串使用单引号 \'\'
// bad
var name = "Bob Parr";
// good
var name = \'Bob Parr\';
// bad
var fullName = "Bob " + this.lastName;
// good
var fullName = \'Bob \' + this.lastName;
2) 超过80个字符的字符串应该使用字符串连接换行
注: 如果过度使用,长字符串连接可能会对性能有影响.
// bad
var errorMessage = \'This is a super long error thatwas thrown because of Batman. When you stop to think about how Batman hadanything to do with this, you would get nowhere fast.\';
// bad
var errorMessage = \'This is a super long error that \
was thrown because of Batman. \
When you stop to think about \
how Batman had anything to do \
with this, you would get nowhere \
fast.\';
// good
var errorMessage = \'This is a super long error that \'+
\'was thrownbecause of Batman.\' +
\'When you stopto think about \' +
\'how Batmanhad anything to do \' +
\'with this,you would get nowhere \' +
\'fast.\';
3) 编程时使用join而不是字符串连接来构建字符串,特别是IE:
var items,
messages,
length, i;
messages = [{
state:\'success\',
message:\'This one worked.\'
},{
state:\'success\',
message:\'This one worked as well.\'
},{
state:\'error\',
message:\'This one did not work.\'
}];
length = messages.length;
// bad
function inbox(messages) {
items =\'<ul>\';
for (i = 0; i< length; i++) {
items +=\'<li>\' + messages[i].message + \'</li>\';
}
return items +\'</ul>\';
}
// good
function inbox(messages) {
items = [];
for (i = 0; i< length; i++) {
items[i] =messages[i].message;
}
return \'<ul><li>\'+ items.join(\'</li><li>\') + \'</li></ul>\';
}
1.1.4.7 函数
1) 函数表达式:
// 匿名函数表达式
var anonymous = function() {
return true;
};
// 有名函数表达式
var named = function named() {
return true;
};
// 立即调用函数表达式
(function() {
console.log(\'Welcome to the Internet. Please follow me.\');
})();
2) 绝对不要在一个非函数块里声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但是它们解析不同。
3) 注: ECMA-262定义把块定义为一组语句,函数声明不是一个语句。阅读ECMA-262对这个问题的说明.
// bad
if (currentUser) {
functiontest() {
console.log(\'Nope.\');
}
}
// good
if (currentUser) {
var test =function test() {
console.log(\'Yup.\');
};
}
4) 绝对不要把参数命名为arguments, 这将会逾越函数作用域内传过来的 arguments 对象.
// bad
function nope(name, options, arguments) {
// ...stuff...
}
// good
function yup(name, options, args) {
// ...stuff...
}
1.1.4.8 属性
1) 当使用变量访问属性时使用中括号.
var luke= {
jedi: true,
age: 28
};
functiongetProp(prop) {
return luke[prop];
}
varisJedi = getProp(\'jedi\');
1.1.4.9变量
1) 总是使用 var 来声明变量,如果不这么做将导致产生全局变量,我们要避免污染全局命名空间。
// bad
superPower = new SuperPower();
// good
var superPower = new SuperPower();
2) 使用一个 var 以及新行声明多个变量,缩进4个空格。
// bad
var items = getItems();
var goSportsTeam = true;
var dragonball = \'z\';
// good
var items = getItems(),
goSportsTeam= true,
dragonball =\'z\';
3) 最后再声明未赋值的变量,当你想引用之前已赋值变量的时候很有用。
// bad
var i, len, dragonball,
items =getItems(),
goSportsTeam= true;
// bad
var i, items = getItems(),
dragonball,
goSportsTeam= true,
len;
// good
var items = getItems(),
goSportsTeam= true,
dragonball,
length,
i;
4) 在作用域顶部声明变量,避免变量声明和赋值引起的相关问题。
// bad
function() {
test();
console.log(\'doing stuff..\');
//..otherstuff..
var name =getName();
if (name ===\'test\') {
returnfalse;
}
return name;
}
// good
function() {
var name =getName();
test();
console.log(\'doing stuff..\');
//..otherstuff..
if (name ===\'test\') {
returnfalse;
}
return name;
}
// bad
function() {
var name =getName();
if(!arguments.length) {
returnfalse;
}
return true;
}
// good
function() {
if(!arguments.length) {
returnfalse;
}
var name =getName();
return true;
}
1.1.4.10 变量赋值时的逻辑操作
逻辑操作符“||”和“&&”也可被用来返回布尔值。如果操作对象为非布尔对象,那每个表达式将会被自左向右地做真假判断。基于此操作,最终总有一个表达式被返回。这在变量赋值时,是可以用来简化你的代码的。
不推荐
推荐
这一小技巧经常用来给方法设定默认的参数。
1.1.4.11 总是使用带类型判断的比较判断
总是使用 ===精确的比较操作符,避免在判断的过程中,由 JavaScript 的强制类型转换所造成的困扰。
如果你使用=== 操作符,那比较的双方必须是同一类型为前提的条件下才会有效。
在只使用 == 的情况下,JavaScript 所带来的强制类型转换使得判断结果跟踪变得复杂,下面的例子可以看出这样的结果有多怪了:
1.1.4.12 条件表达式和等号
1) 适当使用 === 和 !== 以及 == 和 !=.
2) 条件表达式的强制类型转换遵循以下规则:
if ([0]) {
// true
// An array isan object, objects evaluate to true
}
a) 对象 被计算为 true
b) Undefined 被计算为 false
c) Null 被计算为 false
d) 布尔值 被计算为 布尔的值
e) 数字 如果是 +0,-0, or NaN 被计算为 false , 否则为true
f) 字符串 如果是空字符串\'\' 则被计算为 false, 否则为 true
3) 使用快捷方式.
// bad
if (name !== \'\') {
// ...stuff...
}
// good
if (name) {
// ...stuff...
}
// bad
if (collection.length > 0) {
// ...stuff...
}
// good
if (collection.length) {
// ...stuff...
}
1.1.4.13 块
1) 给所有多行的块使用大括号
// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function() { return false; }
// good
function() {
return false;
}
1.1.4.14 空白
1) 将tab设为4个空格
// bad
function() {
∙∙var name;
}
// bad
function() {
∙var name;
}
// good
function() {
∙∙∙∙var name;
}
2) 大括号前放一个空格
// bad
function test(){
console.log(\'test\');
}
// good
function test() {
console.log(\'test\');
}
// bad
dog.set(\'attr\',{
age: \'1 year\',
breed:\'Bernese Mountain Dog\'
});
// good
dog.set(\'attr\', {
age: \'1 year\',
breed:\'Bernese Mountain Dog\'
});
3) 在做长方法链时使用缩进.
// bad
$(\'#items\').find(\'.selected\').highlight().end().find(\'.open\').updateCount();
// good
$(\'#items\')
.find(\'.selected\')
.highlight()
.end()
.find(\'.open\')
.updateCount();
// bad
var leds =stage.selectAll(\'.led\').data(data).enter().append(\'svg:svg\').class(\'led\', true)
.attr(\'width\', (radius + margin)* 2).append(\'svg:g\')
.attr(\'transform\', \'translate(\' + (radius + margin) + \',\' + (radius +margin) + \')\')
.call(tron.led);
// good
var leds = stage.selectAll(\'.led\')
.data(data)
.enter().append(\'svg:svg\')
.class(\'led\', true)
.attr(\'width\', (radius + margin)* 2)
.append(\'svg:g\')
.attr(\'transform\', \'translate(\' + (radius + margin) + \',\' + (radius +margin) + \')\')
.call(tron.led);
1.1.4.15 逗号
1) 不要将逗号放前面
// bad
var once
, upon
, aTime;
// good
var once,
upon,
aTime;
// bad
var hero = {
firstName: \'Bob\'
, lastName: \'Parr\'
, heroName: \'Mr. Incredible\'
, superPower: \'strength\'
};
// good
var hero = {
firstName: \'Bob\',
lastName: \'Parr\',
heroName: \'Mr. Incredible\',
superPower: \'strength\'
};
2) 不要加多余的逗号,这可能会在IE下引起错误,同时如果多一个逗号某些ES3的实现会计算多数组的长度。
// bad
var hero = {
firstName: \'Kevin\',
lastName: \'Flynn\',
};
var heroes = [
\'Batman\',
\'Superman\',
];
// good
var hero = {
firstName: \'Kevin\',
lastName: \'Flynn\'
};
var heroes = [
\'Batman\',
\'Superman\'
];
1.1.4.16 分号
1) 语句结束一定要加分号
// bad
(function() {
var name = \'Skywalker\'
return name
})()
// good
(function() {
var name = \'Skywalker\';
return name;
})();
// good
;(function() {
var name = \'Skywalker\';
return name;
})();
2) 澄清:分号与函数
分号需要用在表达式的结尾,而并非函数声明的结尾。区分它们最好的例子是:
1.1.4.17 语句块内的函数声明
切勿在语句块内声明函数,在 ECMAScript 5 的严格模式下,这是不合法的。函数声明应该在定义域的顶层。但在语句块内可将函数申明转化为函数表达式赋值给变量。
不推荐
推荐
1.1.4.18 类型转换
1) 在语句的开始执行类型转换.
2) 字符串:
// =>this.reviewScore = 9;
// bad
var totalScore = this.reviewScore + \'\';
// good
var totalScore = \'\' + this.reviewScore;
// bad
var totalScore = \'\' + this.reviewScore + \' totalscore\';
// good
var totalScore = this.reviewScore + \' total score\';
3) 对数字使用parseInt 并且总是带上类型转换的基数.
var inputValue = \'4\';
// bad
var val = new Number(inputValue);
// bad
var val = +inputValue;
// bad
var val = inputValue >> 0;
// bad
var val = parseInt(inputValue);
// good
var val = Number(inputValue);
// good
var val = parseInt(inputValue, 10);
// good
/**
* parseInt wasthe reason my code was slow.
* Bitshiftingthe String to coerce it to a
* Number madeit a lot faster.
*/
var val = inputValue >> 0;
4) 布尔值:
var age = 0;
// bad
var hasAge = new Boolean(age);
// good
var hasAge = Boolean(age);
// good
var hasAge = !!age;
1.1.4.19 存取器
1) 属性的存取器函数不是必需的
2) 如果你确实有存取器函数的话使用getVal() 和 setVal(\'hello\')
// bad
dragon.age();
// good
dragon.getAge();
// bad
dragon.age(25);
// good
dragon.setAge(25);
3) 如果属性是布尔值,使用isVal()或 hasVal()
// bad
if (!dragon.age()) {
return false;
}
// good
if (!dragon.hasAge()) {
return false;
}
4) 可以创建get()和set()函数,但是要保持一致
function Jedi(options) {
options ||(options = {});
var lightsaber= options.lightsaber || \'blue\';
this.set(\'lightsaber\', lightsaber);
}
Jedi.prototype.set = function(key, val) {
this[key] =val;
};
Jedi.prototype.get = function(key) {
returnthis[key];
};
1.1.4.20 构造器
1) 给对象原型分配方法,而不是用一个新的对象覆盖原型,覆盖原型会使继承出现问题。
function Jedi() {
console.log(\'new jedi\');
}
// bad
Jedi.prototype = {
fight:function fight() {
console.log(\'fighting\');
},
block:function block() {
console.log(\'blocking\');
}
};
// good
Jedi.prototype.fight = function fight() {
console.log(\'fighting\');
};
Jedi.prototype.block = function block() {
console.log(\'blocking\');
};
2) 方法可以返回 this 帮助方法可链。
// bad
Jedi.prototype.jump = function() {
this.jumping =true;
return true;
};
Jedi.prototype.setHeight = function(height) {
this.height =height;
};
var luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20) // => undefined
// good
Jedi.prototype.jump = function() {
this.jumping =true;
return this;
};
Jedi.prototype.setHeight = function(height) {
this.height =height;
return this;
};
var luke = new Jedi();
luke.jump()
.setHeight(20);
3) 可以写一个自定义的toString()方法,但是确保它工作正常并且不会有副作用。
function Jedi(options) {
options ||(options = {});
this.name =options.name || \'no name\';
}
Jedi.prototype.getName = function getName() {
returnthis.name;
};
Jedi.prototype.toString = function toString() {
return \'Jedi -\' + this.getName();
};
1.1.4.21 事件
1) 当给事件附加数据时,传入一个哈希而不是原始值,这可以让后面的贡献者加入更多数据到事件数据里而不用找出并更新那个事件的事件处理器
// bad
$(this).trigger(\'listingUpdated\', listing.id);
...
$(this).on(\'listingUpdated\', function(e, listingId) {
// dosomething with listingId
});
// good
$(this).trigger(\'listingUpdated\', { listingId :listing.id });
...
$(this).on(\'listingUpdated\', function(e, data) {
// dosomething with data.listingId
});
1.1.4.22 模块
1) 模块应该以 ! 开始,这保证了如果一个有问题的模块忘记包含最后的分号在合并后不会出现错误
2) 这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致
3) 加入一个名为noConflict()的方法来设置导出的模块为之前的版本并返回它
4) 总是在模块顶部声明\'use strict\';
// fancyInput/fancyInput.js
!function(global) {
\'use strict\';
varpreviousFancyInput = global.FancyInput;
functionFancyInput(options) {
this.options= options || {};
}
FancyInput.noConflict = function noConflict() {
global.FancyInput = previousFancyInput;
returnFancyInput;
};
global.FancyInput = FancyInput;
}(this);
1.1.4.23 使用jQuery规范
1) 缓存jQuery查询
// bad
function setSidebar() {
$(\'.sidebar\').hide();
// ...stuff...
$(\'.sidebar\').css({
\'background-color\': \'pink\'
});
}
// good
function setSidebar() {
var $sidebar =$(\'.sidebar\');
$sidebar.hide();
// ...stuff...
$sidebar.css({
\'background-color\': \'pink\'
});
}
2) 对DOM查询使用级联的 $(\'.sidebar ul\') 或 $(\'.sidebar ul\'),
3) 对有作用域的jQuery对象查询使用 find
// bad
$(\'.sidebar\', \'ul\').hide();
// bad
$(\'.sidebar\').find(\'ul\').hide();
// good
$(\'.sidebar ul\').hide();
// good
$(\'.sidebar > ul\').hide();
// good (slower)
$sidebar.find(\'ul\');
// good (faster)
$($sidebar[0]).find(\'ul\');
1.1.4.24标准特性
总是优先考虑使用标准特性。为了最大限度地保证扩展性与兼容性,总是首选标准的特性,而不是非标准的特性(例如:首选 string.charAt(3) 而不是 string[3];首选 DOM 的操作方法来获得元素引用,而不是某一应用特定的快捷方法)。
1.1.4.25 简易的原型继承
在 JavaScript 中继承对象时,遵循使用一个简易的模式来创建此继承。如果遇上复杂对象的继承,那考虑采用一个继承库。
简易继承请用以下方式:
1.1.4.26 使用闭包
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。 使用闭包的两个场景:一个是读取函数内部的变量,另一个是让函数内变量的值始终保持在内存中。
1.1.4.27 切勿在循环中创建函数
在简单的循环语句中加入函数是非常容易形成闭包而带来隐患的。下面的例子就是一个典型的陷阱:
不推荐
接下来的改进虽然已经解决了上述例子中的问题或 bug,但还是违反了不在循环中创建函数或闭包的原则。
不推荐
接下来的改进已解决问题,而且也遵循了规范。可是,你会发现看上去似乎过于复杂繁冗了,应该会有更好的解决方案吧。
不完全推荐
将循环语句转换为函数执行的方式问题能得到立马解决,每一次循环都会对应地创建一次闭包。函数式的风格更加值得推荐,而且看上去也更加地自然和可预料。
推荐
1.1.4.28 eval函数
尽量不要使用 evil 函数。eval()不但混淆语境还很危险,总会有比这更好、更清晰、更安全的另一种方案来写你的代码。
1.1.4.29 this关键字
只在对象构造器、方法和在设定的闭包中使用 this 关键字。this 的语义容易有误导,它时而指向全局对象(大多数时),时而指向调用者的定义域(在eval 中),时而指向 DOM 树中的某一节点(当用事件处理绑定到 HTML 属性上时),时而指向一个新创建的对象(在构造器中),还时而指向其它的一些对象。
正因为它是如此容易地被搞错,请限制它的使用场景:
1) 在构造函数中
2) 在对象的方法中(包括由此创建出的闭包内)
1.1.4.30 函数式编程
函数式编程可以简化代码并缩减维护成本,容易复用、解耦、更少的依赖。
例外:往往在“重代码性能,轻代码维护”的情况之下,要选择最优性能的解决方案而非维护性高的方案(比如用简单的循环语句代替 forEach)。
1.1.4.31 注释
注释是了解代码写法和目的的唯一途径。注释用于描述“代码都做了什么,代码为什么要这么写”。可以加入所思考问题或解决方案的链接地址。