Properties
• 当访问属性的时候,我们使用点(.)操作符。
var luke = { jedi: true, age: 28 }; // bad var isJedi = luke['jedi']; // good var isJedi = luke.jedi;
• 当以变量的方式访问属性的时候,用下标符号([])。——除非特殊需求,否则尽量避免使用obj[variable]的方式进行属性访问。
var luke = { jedi: true, age: 28 }; function getProp(prop) { return luke[prop]; } var isJedi = getProp('jedi');
Variables
• 总是使用var定义变量,否则会导致产生隐含全局变量。我们要尽量避免污染全局变量命名空间。
// bad superPower = new SuperPower(); // good var superPower = new SuperPower();
汤姆大叔—javascript系列文章中提到“JavaScript有隐含的全局概念,意味着你不声明的任何变量都会成为一个全局对象属性。在技术上,隐式全局变量并不是真正的全局变量,但它们是全局对象的属性。属性是可以通过
delete
操作符删除的,而变量是不能的。"
• 使用一个var定义多个变量,每个变量在一个新行上。
// bad var items = getItems(); var goSportsTeam = true; var dragonball = 'z'; // good var items = getItems(), goSportsTeam = true, dragonball = 'z';
• 用var定义多个变量的时候,把不进行赋值的变量放置到最后——这是相当有益的。尤其是当你的变量需要赋前面变量值的时候。
// 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;
• 把你的赋值变量放置在当前作用域的顶端。这将避免变量声明和hoisting(悬置/置顶解析/预解析)的问题。
// bad function() { test(); console.log('doing stuff..'); //..other stuff.. var name = getName(); if (name === 'test') { return false; } return name; } // good function() { var name = getName(); test(); console.log('doing stuff..'); //..other stuff.. if (name === 'test') { return false; } return name; } // bad function() { var name = getName(); if (!arguments.length) { return false; } return true; } // good function() { if (!arguments.length) { return false; } var name = getName(); return true; }
Hoisting
汤姆大叔:1、JavaScript中,你可以在函数的任何位置声明多个var语句,并且它们就好像是在函数顶部声明一样发挥作用,这种行为称为 hoisting(悬置/置顶解析/预解析)。2、对于JavaScript,只 要你的变量是在同一个作用域中(同一函数),它都被当做是声明的,即使是它在var声明前使用的时候。
• 变量声明提升到当前作用域的顶端,而它们的赋值操作不一定要这么做。
function example() { console.log(notDefined); // => throws a ReferenceError } function example() { console.log(declaredButNotAssigned); // => undefined var declaredButNotAssigned = true; } function example() { var declaredButNotAssigned; console.log(declaredButNotAssigned); // => undefined declaredButNotAssigned = true; }
• 匿名表达式会自动提升它们的变量名称(也就是说在var anonymous上面,example函数就已经知道有这个变量了),但是它们的函数体不会。
function example() { console.log(anonymous); // => undefined anonymous(); // => TypeError anonymous is not a function var anonymous = function() { console.log('anonymous function expression'); }; }
• 命名函数表达式也会提升它们的变量名称,而它们的函数名称和函数体不会这样做。
function example() { console.log(named); // => undefined named(); // => TypeError named is not a function superPower(); // => ReferenceError superPower is not defined var named = function superPower() { console.log('Flying'); }; function example() { console.log(named); // => undefined named(); // => TypeError named is not a function var named = function named() { console.log('named'); }; } }
• 注意:函数声明会提升它们的变量名称还有它们的函数体。
function example() { superPower(); // => Flying function superPower() { console.log('Flying'); } }
Conditional Expressions & Equality
• 使用 === 和 !== 代替==和!=。
== 和 != 会进行隐式类型转换,所以建议使用===和!==。
• 强制使用对象的特性(ToBoolean)得到条件表达式的值,大致遵循以下简单规则。
◊ Objects 得到的值是true。
◊ Undefined得到的值是false。
◊ Null得到的值是false。
◊ Booleans得到的值是Boolean值(呵呵,当然)。
◊ Numbers 得到的值是:如果是+0,-0,或者NaN就是false,否则就是true。
◊ Strings 得到的值是:如果是'',就是false,否则就是true。
if ([0]) { // true // An array is an object, objects evaluate to true }
• 使用快捷方式。
// bad if (name !== '') { // ...stuff... } // good if (name) { // ...stuff... } // bad if (collection.length > 0) { // ...stuff... } // good if (collection.length) { // ...stuff... }
Blocks
• 有{}的代码,我们换行处理。
// bad if (test) return false; // good if (test) return false; // good if (test) { return false; } // bad function() { return false; } // good function() { return false; }
Comments
• 对于多行注释使用/** ... */。包含描述信息、参数类型和返回值。
// bad // make() returns a new element // based on the passed in tag name // // @param <String> tag // @return <Element> element function make(tag) { // ...stuff... return element; } // good /** * make() returns a new element * based on the passed in tag name * * @param <String> tag * @return <Element> element */ function make(tag) { // ...stuff... return element; }
• 对于单行注释使用//。单行注释单独放置在一个新行上。在注释前面放置一个空行。
// bad var active = true; // is current tab // good // is current tab var active = true; // bad function getType() { console.log('fetching type...'); // set the default type to 'no type' var type = this._type || 'no type'; return type; } // good function getType() { console.log('fetching type...'); // set the default type to 'no type' var type = this._type || 'no type'; return type; }
• 对于一些问题,注释前加FIXME或TODO,这样将快速帮助开发者快速明白代码意图。
• 使用 // FIXME: 注释问题
function Calculator() { // FIXME: shouldn't use a global here total = 0; return this; }
• 使用 // TODO: 注释问题的解决方案
function Calculator() { // TODO: total should be configurable by an options param this.total = 0; return this; }
Type Casting & Coercion
• 在声明之前执行强制类型转换。
• 字符串
// => this.reviewScore = 9; // bad var totalScore = this.reviewScore + ''; // good var totalScore = '' + this.reviewScore; // bad var totalScore = '' + this.reviewScore + ' total score'; // good var totalScore = this.reviewScore + ' total score';
• 对于数字转换,使用parseInt,而且要带着类型转换的基数。
• 如果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 使我的代码变慢. * 为了提高速度,使用位移操作让字符串强制转化为数字。 */ var val = inputValue >> 0;
• 布尔
var age = 0; // bad var hasAge = new Boolean(age); // good var hasAge = Boolean(age); // good var hasAge = !!age;
Constructors
• 用方法扩展对象,而不是用一个新对象。
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'); };
• 让对象的方法return 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);
• 我们可以自定义一个toString()方法。——要确保它能正常运行,而且不会产生其他影响。
function Jedi(options) { options || (options = {}); this.name = options.name || 'no name'; } Jedi.prototype.getName = function getName() { return this.name; }; Jedi.prototype.toString = function toString() { return 'Jedi - ' + this.getName(); };