JavaScript Style Guide

原文:https://github.com/airbnb/javascript

JavaScript范例

内容列表

  1. 范例

  2. 对象

  3. 数组

  4. 字符串

  5. 函数

  6. 属性

  7. 变量

  8. 前提表达式和等号

  9. 解释

  10. 空缺

  11. 逗号

  12. 分号

  13. 范例转换

  14. 定名商定

  15. 存取器

  16. 组织器

  17. 事宜

  18. 模块

  19. jQuery

  20. ES5 兼容性

  21. 机能

  22. 资本

  23. 哪些人在运用

  24. 翻译

  25. JavaScript作风指南

  26. 贡献者

  27. 许可

范例

  • 原始值: 相当于传值

    • string

    • number

    • boolean

    • null

    • undefined

var foo = 1,
    bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9
  • 庞杂范例: 相当于传援用

    • object

    • array

    • function

var foo = [1, 2],
    bar = foo;

bar[0] = 9;

console.log(foo[0], bar[0]); // => 9, 9
**[[⬆]](#TOC)**

对象

  • 运用字面值建立对象

// bad
var item = new Object();

// good
var item = {};
// bad
var superman = {
  class: 'superhero',
  default: { clark: 'kent' },
  private: true
};

// good
var superman = {
  klass: 'superhero',
  defaults: { clark: 'kent' },
  hidden: true
};

**[[⬆]](#TOC)**

数组

  • 运用字面值建立数组

// 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,
    itemsCopy = [],
    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);
  ...
}
**[[⬆]](#TOC)**

字符串

  • 对字符串运用单引号 ''

// 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.';
  • 编程时运用join而不是字符串衔接来构建字符串,特别是IE: jsPerf.

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>';
}
**[[⬆]](#TOC)**

函数

  • 函数表达式:

// 匿名函数表达式
var anonymous = function() {
  return true;
};

// 著名函数表达式
var named = function named() {
  return true;
};

// 马上挪用函数表达式
(function() {
  console.log('Welcome to the Internet. Please follow me.');
})();
  • 绝对不要在一个非函数块里声明一个函数,把谁人函数赋给一个变量。浏览器许可你这么做,然则它们剖析差别。

  • 注: ECMA-262定义把定义为一组语句,函数声明不是一个语句。浏览ECMA-262对这个题目的申明.

// bad
if (currentUser) {
  function test() {
    console.log('Nope.');
  }
}

// good
if (currentUser) {
  var test = function test() {
    console.log('Yup.');
  };
}
  • 绝对不要把参数定名为 arguments, 这将会跨越函数作用域内传过来的 arguments 对象.

// bad
function nope(name, options, arguments) {
  // ...stuff...
}

// good
function yup(name, options, args) {
  // ...stuff...
}
**[[⬆]](#TOC)**

属性

  • 当运用变量接见属性时运用中括号.

var luke = {
  jedi: true,
  age: 28
};

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

var isJedi = getProp('jedi');
**[[⬆]](#TOC)**

变量

  • 老是运用 var 来声明变量,假如不这么做将致使发生全局变量,我们要防止污染全局定名空间。

// bad
superPower = new SuperPower();

// good
var superPower = new SuperPower();
  • 运用一个 var 以及新行声明多个变量,缩进4个空格。

// bad
var items = getItems();
var goSportsTeam = true;
var dragonball = 'z';

// good
var items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';
  • 末了再声明未赋值的变量,当你想援用之前已赋值变量的时刻很有效。

// 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;
  • 在作用域顶部声明变量,防止变量声明和赋值引发的相干题目。

// 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;
}
**[[⬆]](#TOC)**

前提表达式和等号

  • 恰当运用 ===!== 以及 ==!=.

  • 前提表达式的强迫范例转换遵照以下划定规矩:

    • 对象 被盘算为 true

    • Undefined 被盘算为 false

    • Null 被盘算为 false

    • 布尔值 被盘算为 布尔的值

    • 数字 假如是 +0, -0, or NaN 被盘算为 false , 否则为 true

    • 字符串 假如是空字符串 '' 则被盘算为 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;
}
**[[⬆]](#TOC)**

解释

  • 运用 /** ... */ 举行多行解释,包括形貌,指定范例以及参数值和返回值

// 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;
}
  • 假如你有一个题目须要从新来看一下或假如你发起一个须要被完成的解决要领的话须要在你的解释前面加上 FIXMETODO 协助其他人敏捷明白

function Calculator() {

  // FIXME: shouldn't use a global here
  total = 0;

  return this;
}
function Calculator() {

  // TODO: total should be configurable by an options param
  this.total = 0;

  return this;
}
**[[⬆]](#TOC)**

空缺

  • 将tab设为4个空格

// 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'
});
  • 在做长要领链时运用缩进.

// 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);
**[[⬆]](#TOC)**

逗号

  • 不要将逗号放前面

// 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'
};
  • 不要加过剩的逗号,这能够会在IE下引发毛病,同时假如多一个逗号某些ES3的完成会盘算多数组的长度。

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

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

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

var heroes = [
  'Batman',
  'Superman'
];
**[[⬆]](#TOC)**

分号

  • 语句完毕一定要加分号

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

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

// good
;(function() {
  var name = 'Skywalker';
  return name;
})();
**[[⬆]](#TOC)**

范例转换

  • 在语句的最先实行范例转换.

  • 字符串:

//  => 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 而且老是带上范例转换的基数.

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 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;
  • 布尔值:

var age = 0;

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

// good
var hasAge = Boolean(age);

// good
var hasAge = !!age;
**[[⬆]](#TOC)**

定名商定

  • 防止单个字符名,让你的变量名有形貌意义。

// bad
function q() {
  // ...stuff...
}

// good
function query() {
  // ..stuff..
}
  • 当定名对象、函数和实例时运用驼峰定名划定规矩

// bad
var OBJEcttsssss = {};
var this_is_my_object = {};
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);
  };
}
**[[⬆]](#TOC)**

存取器

  • 属性的存取器函数不是必须的

  • 假如你确切有存取器函数的话运用getVal() 和 setVal(‘hello’)

// bad
dragon.age();

// good
dragon.getAge();

// bad
dragon.age(25);

// good
dragon.setAge(25);
  • 假如属性是布尔值,运用isVal() 或 hasVal()

// bad
if (!dragon.age()) {
  return false;
}

// good
if (!dragon.hasAge()) {
  return false;
}
  • 能够建立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) {
  return this[key];
};
**[[⬆]](#TOC)**

组织器

  • 给对象原型分派要领,而不是用一个新的对象掩盖原型,掩盖原型会使继续涌现题目。

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();
};
**[[⬆]](#TOC)**

事宜

  • 当给事宜附加数据时,传入一个哈希而不是原始值,这能够让背面的贡献者到场更多数据到事宜数据里而不必找出并更新谁人事宜的事宜处理器

// bad
$(this).trigger('listingUpdated', listing.id);

...

$(this).on('listingUpdated', function(e, listingId) {
  // do something with listingId
});
更好:
// good
$(this).trigger('listingUpdated', { listingId : listing.id });

...

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

[⬆]

模块

  • 模块应当以 ! 最先,这保证了假如一个有题目的模块遗忘包括末了的分号在兼并后不会涌现毛病

  • 这个文件应当以驼峰定名,并在同名文件夹下,同时导出的时刻名字一致

  • 到场一个名为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);
**[[⬆]](#TOC)**

jQuery

  • 缓存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'
  });
}
  • 对DOM查询运用级联的 $('.sidebar ul')$('.sidebar ul')jsPerf

  • 对有作用域的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');
**[[⬆]](#TOC)**

许可

(The MIT License)

Copyright (c) 2012 Airbnb

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
‘Software’), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

[⬆]

};

    原文作者:3Sharp
    原文地址: https://segmentfault.com/a/1190000003500229
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞