【譯】JavaScript最全編碼規範

類型

基本類型:訪問基本類型時,應該直接操做類型值

  • string
  • number
  • boolean
  • null
  • undefined
javascriptvar foo = 1;
var bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9

複合類型:訪問複合類型時,應該操做其引用

  • object
  • array
  • function
var foo = [1, 2];
var bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9

對象

  • 使用字面量語法建立對象
// bad
var item = new Object();
// good
var item = {};
  • 不要使用保留字,在IE8中不起做用,更多相關信息
// bad
var superman = {
  default: { clark: 'kent' },
  private: true
};

// good
var superman = {
  defaults: { clark: 'kent' },
  hidden: true
};
  • 使用易讀的同義詞代替保留字
// bad
var superman = {
  class: 'alien'
};

// bad
var superman = {
  klass: 'alien'
};

// good
var superman = {
  type: 'alien'
};

數組

  • 使用字面量語法建立數組
// bad
var items = new Array();

// good
var items = [];
  • 添加數組元素時,使用push而不是直接添加
var someStack = [];


// bad
someStack[someStack.length] = 'abracadabra';

// good
someStack.push('abracadabra');
  • 須要複製數組時,可使用slice,jsPerf的相關文章
var len = items.length;
var itemsCopy = [];
var i;

// bad
for (i = 0; i < len; i++) {
  itemsCopy[i] = items[i];
}

// good
itemsCopy = items.slice();
  • 使用slice將類數組對象轉爲數組
function trigger() {
  var args = Array.prototype.slice.call(arguments);
  ...
}

字符串

  • 對字符串使用單引號
// bad
var name = "Bob Parr";

// good
var name = 'Bob Parr';

// bad
var fullName = "Bob " + this.lastName;

// good
var fullName = 'Bob ' + this.lastName;
  • 超過80個字符的字符串應該使用字符串鏈接符進行跨行
  • 注意:對長字符串過分使用鏈接符將會影響性能。相關的文章和主題討論: jsPerf & Discussion.
// 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.';

// 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 thrown because ' +
  'of Batman. When you stop to think about how Batman had anything to do ' +
  'with this, you would get nowhere fast.';
  • 以編程方式建立字符串的時應該使用Array的join方法而不是經過鏈接符,尤爲是在IE中:jsPerf.
var items;
var messages;
var length;
var 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] = '<li>' + messages[i].message + '</li>';
  }

  return '

<ul>' + items.join('') + '</ul>

';
}

函數

  • 函數表達式
// anonymous function expression
var anonymous = function() {
  return true;
};

// named function expression
var named = function named() {
  return true;
};

// immediately-invoked function expression (IIFE)
(function() {
  console.log('Welcome to the Internet. Please follow me.');
})();
  • 不要在非函數塊中(if, while, etc)聲明函數,儘管瀏覽器容許你分配函數給一個變量,但壞消息是,不一樣的瀏覽器用不一樣的方式解析它
  • 注意:ECMA-262把塊定義爲一組語句,但函數聲明不是一個語句:Read ECMA-262’s note
    on this issue
    .
// bad
if (currentUser) {
  function test() {
    console.log('Nope.');
  }
}

// good
var test;
if (currentUser) {
  test = function test() {
    console.log('Yup.');
  };
}
  • 不要命名一個參數爲arguments,不然它將優先於傳遞給每一個函數做用域中的arguments對象,
// bad
function nope(name, options, arguments) {
  // ...stuff...
}

// good
function yup(name, options, args) {
  // ...stuff...
}

屬性

  • 使用點表示法訪問屬性
var luke = {
  jedi: true,
  age: 28
};

// bad
var isJedi = luke['jedi'];

// good
var isJedi = luke.jedi;
  • 用變量訪問屬性時要使用下標表示法([])
var luke = {
  jedi: true,
  age: 28
};

function getProp(prop) {
  return luke[prop];
}

var isJedi = getProp('jedi');

變量

  • 老是使用var聲明變量,否則其將變爲全局變量。咱們要想辦法避免全局空間污染
// bad
superPower = new SuperPower();

// good
var superPower = new SuperPower();
  • 使用var聲明每一個變量,這樣很容易添加新的變量聲明,而不用去擔憂用a;替換a,
// bad
var items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';

// bad
// (compare to above, and try to spot the mistake)
var items = getItems(),
    goSportsTeam = true;
    dragonball = 'z';

// good
var items = getItems();
var goSportsTeam = true;
var dragonball = 'z';
  • 最後聲明未賦值的變量,這對於你須要根據以前已經賦值的變量對一個變量進行賦值時是頗有幫助的
// bad
var i, len, dragonball,
    items = getItems(),
    goSportsTeam = true;

// bad
var i;
var items = getItems();
var dragonball;
var goSportsTeam = true;
var len;

// good
var items = getItems();
var goSportsTeam = true;
var dragonball;
var length;
var i;
  • 在做用域頂端對變量賦值,這有助於避免變量聲明問題和與聲明提高相關的問題
// 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;
}

聲明提高

  • 變量聲明是在做用域的頂端,可是賦值沒有
// we know this wouldn't work (assuming there
// is no notDefined global variable)
function example() {
  console.log(notDefined); // => throws a ReferenceError
}

// creating a variable declaration after you
// reference the variable will work due to
// variable hoisting. Note: the assignment
// value of `true` is not hoisted.
function example() {
  console.log(declaredButNotAssigned); // => undefined
  var declaredButNotAssigned = true;
}

// The interpreter is hoisting the variable
// declaration to the top of the scope,
// which means our example could be rewritten as:
function example() {
  var declaredButNotAssigned;
  console.log(declaredButNotAssigned); // => undefined
  declaredButNotAssigned = true;
}
  • 匿名錶達式能提高他們的變量名,但不能提高函數賦值
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');
  };
}

// the same is true when the function name
// is the same as the variable name.
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');
  }
}

更多信息指引:JavaScript Scoping & Hoisting by Ben Cherry.javascript

比較運算符&相等

  • 使用===和!==代替==和!=
  • 比較運算符進行計算時會利用ToBoolean方法進行強制轉換數據類型,並聽從一下規則
    >Objects的計算值是true
    >Undefined的計算值是false
    >Boolean的計算值是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...
}

語句塊

  • 對多行的語句塊使用大括號
// bad
if (test)
  return false;

// good
if (test) return false;

// good
if (test) {
  return false;
}

// bad
function() { return false; }

// good
function() {
  return false;
}
  • 對於使用if和else的多行語句塊,把else和if語句塊的右大括號放在同一行
// bad
if (test) {
  thing1();
  thing2();
}
else {
  thing3();
}

// good
if (test) {
  thing1();
  thing2();
} else {
  thing3();
}

註釋

  • 多行註釋使用/** … */,需包含一個描述、全部參數的具體類型和值以及返回值
// 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 or TODO 前綴有利於其餘開發者快速理解。這些註釋不一樣於一般的註釋,由於它們是可實施的。這些實施措施就是FIXME -- need to figure this out or TODO -- need to implement.
    使用// 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;
}

空白

  • 使用軟製表符設置兩個空格
// bad
function() {
∙∙∙∙var name;
}

// bad
function() {
∙var name;
}

// good
function() {
∙∙var name;
}
  • 在左大括號以前留一個空格
// 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'
});
  • 在控制語句中(if, while etc),左括號以前留一個空格。函數的參數列表以前不要有空格
// bad
if(isJedi) {
  fight ();
}

// good
if (isJedi) {
  fight();
}

// bad
function fight () {
  console.log ('Swooosh!');
}

// good
function fight() {
  console.log('Swooosh!');
}
  • 用空白分隔運算符
// bad
var x=y+5;

// good
var x = y + 5;
  • 用一個換行符結束文件
// bad
(function(global) {
  // ...stuff...
})(this);
// bad
(function(global) {
  // ...stuff...
})(this);↵
↵
// good
(function(global) {
  // ...stuff...
})(this);↵
  • 當調用很長的方法鏈時使用縮進,能夠強調這行是方法調用,不是新的語句
// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();

// 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').classed('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')
    .classed('led', true)
    .attr('width',  (radius + margin) * 2)
  .append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);
  • 在語句塊和下一個語句以前留一個空行
// bad
if (foo) {
  return bar;
}
return baz;

// good
if (foo) {
  return bar;
}

return baz;

// bad
var obj = {
  foo: function() {
  },
  bar: function() {
  }
};
return obj;

// good
var obj = {
  foo: function() {
  },

  bar: function() {
  }
};

return obj;

逗號

  • 不要在語句前留逗號
// bad
var story = [
    once
  , upon
  , aTime
];

// good
var story = [
  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'
};
  • 不要有多餘逗號:這會在IE六、IE7和IE9的怪異模式中致使一些問題;同時,在ES3的一些實現中,多餘的逗號會增長數組的長度。在ES5中已經澄清(source
// bad
  var hero = {
    firstName: 'Kevin',
    lastName: 'Flynn',
  };

  var heroes = [
    'Batman',
    'Superman',
  ];

  // good
  var hero = {
    firstName: 'Kevin',
    lastName: 'Flynn'
  };

  var heroes = [
    'Batman',
    'Superman'
  ];

分號

  • 恩,這也是規範一部分
// bad
(function() {
  var name = 'Skywalker'
  return name
})()

// good
(function() {
  var name = 'Skywalker';
  return name;
})();

// good (guards against the function becoming an argument when two files with IIFEs are concatenated)
;(function() {
  var name = 'Skywalker';
  return name;
})();

閱讀更多css

類型分配&強制轉換

  • 執行強制類型轉換的語句。
Strings:
//  => 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對Numbers進行轉換,並帶一個進製做爲參數
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);
  • 不管出於什麼緣由,或許你作了一些」粗野」的事;或許parseInt成了你的瓶頸;或許考慮到性能,須要使用位運算,都要用註釋說明你爲何這麼作
// good
/**
 * parseInt was the reason my code was slow.
 * Bitshifting the String to coerce it to a
 * Number made it a lot faster.
 */
var val = inputValue >> 0;
  • 注意:當使用位運算時,Numbers被視爲64位值,可是位運算老是返回32位整型(source)。對於整型值大於32位的進行位運算將致使不可預見的行爲。Discussion.最大的有符號32位整數是2,147,483,647
2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647
Booleans:
var age = 0;

// bad
var hasAge = new Boolean(age);

// good
var hasAge = Boolean(age);

// good
var hasAge = !!age;

命名規範

  • 避免單字母名稱,讓名稱具備描述性
// bad
function q() {
  // ...stuff...
}

// good
function query() {
  // ..stuff..
}
當命名對象、函數和實例時使用駱駝拼寫法
// bad
var OBJEcttsssss = {};
var this_is_my_object = {};
function c() {}
var u = new user({
  name: 'Bob Parr'
});

// good
var thisIsMyObject = {};
function thisIsMyFunction() {}
var user = new User({
  name: 'Bob Parr'
});
  • 當命名構造函數或類名時,使用駝峯式寫法
// bad
function user(options) {
  this.name = options.name;
}

var bad = new user({
  name: 'nope'
});

// good
function User(options) {
  this.name = options.name;
}

var good = new User({
  name: 'yup'
});
  • 命名私有屬性時使用前置下劃線
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';

// good
this._firstName = 'Panda';
保存this引用時使用_this
// bad
function() {
  var self = this;
  return function() {
    console.log(self);
  };
}

// bad
function() {
  var that = this;
  return function() {
    console.log(that);
  };
}

// good
function() {
  var _this = this;
  return function() {
    console.log(_this);
  };
}
  • 命名函數時,下面的方式有利於堆棧跟蹤
// bad
var log = function(msg) {
  console.log(msg);
};

// good
var log = function log(msg) {
  console.log(msg);
};
  • 注意:IE8和怪異模式下命名函數表示,戳此:http://kangax.github.io/nfe/
    若是文件做爲一個類被導出,文件名應該和類名保持一致
// file contents
class CheckBox {
  // ...
}
module.exports = CheckBox;

// in some other file
// bad
var CheckBox = require('./checkBox');

// bad
var CheckBox = require('./check_box');

// good
var CheckBox = require('./CheckBox');

存取器

  • 對於屬性,訪問器函數不是必須的
  • 若是定義了存取器函數,應參照getVal() 和 setVal(‘hello’)格式.
// bad
dragon.age();

// good
dragon.getAge();

// bad
dragon.age(25);

// good
dragon.setAge(25);
  • 若是屬性時boolean,格式應爲isVal() or hasVal().
// bad
if (!dragon.age()) {
  return false;
}

// good
if (!dragon.hasAge()) {
  return false;
}
  • 建立get() and 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) {
  return this[key];
};

構造函數

  • 在原型對象上定義方法,而不是用新對象重寫它。重寫使繼承變爲不可能:重置原型將重寫整個基類
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');
};
  • 方法應該返回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();
};

事件

  • 當在事件對象上附加數據時(不管是DOM事件仍是如Backbone同樣擁有的私有事件),應傳遞散列對象而不是原始值,這可讓隨後的貢獻者給事件對象添加更多的數據,而沒必要去查找或者更新每個事件處理程序。舉個粟子,不要用下面的方式:
// bad
$(this).trigger('listingUpdated', listing.id);

...

$(this).on('listingUpdated', function(e, listingId) {
  // do something with listingId
});

應該按以下方式:html

// good
$(this).trigger('listingUpdated', { listingId : listing.id });

...

$(this).on('listingUpdated', function(e, data) {
  // do something with data.listingId
});

模塊

  • 模塊應該以 ! 開始,這能確保當腳本鏈接時,若是畸形模塊忘記導入,包括最後一個分號,不會產生錯誤。Explanation
  • 文件應該以駝峯式命名,放在同名的文件夾中,和單出口的名稱相匹配
  • 定義一個noConflict()方法來設置導出模塊以前的版本,並返回當前版本。
  • 在模塊的頂部申明’use strict';
// fancyInput/fancyInput.js

!function(global) {
  'use strict';

  var previousFancyInput = global.FancyInput;

  function FancyInput(options) {
    this.options = options || {};
  }

  FancyInput.noConflict = function noConflict() {
    global.FancyInput = previousFancyInput;
    return FancyInput;
  };

  global.FancyInput = FancyInput;
}(this);

jQuery

  • jQuery對象變量使用前綴$
// bad
var sidebar = $('.sidebar');

// good
var $sidebar = $('.sidebar');
緩存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'
  });
}
  • 使用級聯$(‘.sidebar ul’)或父子$(‘.sidebar > ul’)選擇器進行DOM查詢。jsPerf
  • 在範圍內使用find進行jQuery對象查詢
// bad
$('ul', '.sidebar').hide();

// bad
$('.sidebar').find('ul').hide();

// good
$('.sidebar ul').hide();

// good
$('.sidebar > ul').hide();

// good
$sidebar.find('ul').hide();

譯文出處:http://www.ido321.com/1520.htmljava

相關文章
相關標籤/搜索