成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

JavaScript 編碼規(guī)范

newsning / 2492人閱讀

摘要:論語(yǔ)中各篇一般都是以第一章的前二三個(gè)字作為該篇的篇名。不允許使用命名參數(shù)的優(yōu)先級(jí)高于高于每個(gè)函數(shù)作用域自帶的對(duì)象,這會(huì)導(dǎo)致函數(shù)自帶的值被覆蓋。

類(lèi)型 基本類(lèi)型

你可以直接獲取到基本類(lèi)型的值

string

number

boolean

null

undefined

symbol

const foo = 1;
let bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9
注意Symbols 不能被完整的 polyfill,所以,在不支持 Symbols 的環(huán)境下中,不應(yīng)該使用 symbol 類(lèi)型。
復(fù)雜類(lèi)型

復(fù)雜類(lèi)型賦值就是獲取到他的引用的值,相當(dāng)于引用傳遞

object

array

function

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

bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9
參考 永遠(yuǎn)都使用 const

為了確保你不會(huì)改變你的初始值,重復(fù)引用會(huì)導(dǎo)致一些不可預(yù)見(jiàn)的 bug,還會(huì)讓代碼難以理解,所有的賦值都應(yīng)該使用 const,避免使用 var。

eslint

prefer-const

no-const-assign

// bad
var a = 1;
var b = 2;

// good
const a = 1;
const b = 2;
可以使用 let

如果你一定要對(duì)參數(shù)重新賦值,那就使用 let,而不是 var, let 是塊級(jí)作用域,而 ver 是函數(shù)級(jí)作用域。

eslint

no-var

// bad
var count = 1;
if (true) {
  count += 1;
}

// good
let count = 1;
if (true) {
  count += 1;
}
注意 constlet 的塊級(jí)作用域

constlet 聲明的常量與變量都只存在于定義它們的那個(gè)塊級(jí)作用域中。

{
  let a = 1;
  const b = 1;
}

console.log(a); // ReferenceError
console.log(b); // ReferenceError
對(duì)象 永遠(yuǎn)使用字面量創(chuàng)建對(duì)象

eslint

no-new-object

// bad
const obj = new Object();

// good
const obj = {};
使用計(jì)算屬性名

當(dāng)你需要?jiǎng)?chuàng)建一個(gè)帶有 動(dòng)態(tài)屬性名 的對(duì)象時(shí),請(qǐng)將所有的屬性定義放在一起,可以使用 計(jì)算屬性名。

function getKey(key) {
  return `a key named ${key}`;
}

// bad
const obj = {
  id: 1,
  name: "Parc MG",
};
obj[getKey("enabled")] = true;

// good
const obj = {
  id: 1,
  name: "Parc MG",
  [getKey("enabled")]: true
};
對(duì)象方法簡(jiǎn)寫(xiě)

eslint

object-shorthand

// bad
const atom = {
  value: 1,
  add: function (value) {
    return atom.value + value;
  }
};

// good
const atom = {
  value: 1,
  add(value) {
    return atom.value + value;
  }
};
屬性值縮寫(xiě)

eslint

object-shorthand

const name = "Parc MG";

// bad
const org = {
  name: name,
};

// good
const org = {
  name,
};
將所有屬性值縮寫(xiě)放在對(duì)象聲明的最前面
const name = "Parc MG";
const url = "https://parcmg.com";

// bad
const org = {
  email: "[email protected]",
  name,
  created: new Date(),
  url,
};

// good
const org = {
  name,
  url,
  email: "[email protected]",
  created: new Date(),
};
若非必要,屬性名不使用 "" 號(hào)

eslint

quote-props

// bad
const bad = {
  "foo": 1,
  "bar": 2,
  "foo-bar": 3,
};

// good
const good = {
  foo: 1,
  bar: 2,
  "foo-bar": 3,
};
不直接調(diào)用對(duì)象原型上的方法

不直接調(diào)用一個(gè)對(duì)象的 hasOwnPropertypropertyIsEnumerable、isPrototypeOf 等這些原型的方法,在某些情況下,這些方法可能會(huì)被屏蔽掉,比如 { hasOwnProperty: false } 或者是一個(gè)空對(duì)象 Object.create(null)

// bad
obj.hasOwnProperty(key);

// good
Object.prototype.hasOwnProperty.call(obj, key);

// best
const has = Object.prototype.hasOwnProperty;

has.call(obj, key);
積極使用擴(kuò)展及解構(gòu)運(yùn)算 ...

在對(duì)象的 淺拷貝 時(shí),更推薦使用擴(kuò)展運(yùn)算 { ...obj },而不是 Object.assign。

在獲取對(duì)象指定的幾個(gè)屬性時(shí),使用解構(gòu)運(yùn)算 { foo, bar, ...rest } = obj

eslint

prefer-destructuring

// very bad
const original = { a: 1, b: 2 };
const copied = Object.assign(original, { c: 3 }); // 這將導(dǎo)致 original 也被修改

delete copied.a; // 這樣操作之后會(huì)導(dǎo)致 original 也被修改
console.log(original); // => {b: 2, c: 3}

// bad
const original = { a: 1, b: 2 };
const copied = Object.assign({}, original, { c: 3}};

// good
const original = { a: 1, b: 2 };
const copied = { ...original, c: 3 };

// 解構(gòu)運(yùn)算與 `rest` 賦值運(yùn)算
const obj = { a: 1, b: 2, c: 3 };
const { a, b } = obj; // 從對(duì)象 obj 中解構(gòu)出 a, b 兩個(gè)屬性的值,并賦值給名為 a,b 的常量
const { a, ...rest } = obj; // 從對(duì)象 obj 中解構(gòu)出 a 的值,并賦值給名為 a 的常量,同時(shí),創(chuàng)建一個(gè)由所有其它屬性組成的名為 `rest` 的新對(duì)象
console.log(rest); // => { b: 2, c: 3 }

// bad
function getFullName(user) {
  const firstName = user.firstName;
  const lastName = user.lastName;
  
  return `${firstName} ${lastName}`;
}

// good
function getFullName(user) {
  const { firstName, lastName } = user;
  return `${firstName} ${lastName}`;
}

// best
function getFullName({ firstName, lastName}) {
  return `${firstName} ${lastName}`;
}

// the most best
const getFullName = ({ firstName, lastName }) => `${firstName} ${lastName}`;
返回多值時(shí),使用對(duì)象解構(gòu),而非數(shù)組結(jié)構(gòu)

由于 JavaScript 不支持多值返回,當(dāng)一個(gè)函數(shù)或者方法有多個(gè)值需要?jiǎng)?chuàng)建時(shí),請(qǐng)為每一個(gè)值命名,并以所有值組成的對(duì)象為單一值返回,而不是以數(shù)組的形式返回。

// bad
function processInput(input) {
  return [left, right, top, bottom];
}

const [left, _, top] = processInput(input); // 調(diào)用者需要在調(diào)用時(shí),明確的知道每一個(gè)索引上的值是什么 ,且無(wú)法跳越前面的值取后面的值

// good
function processInput(input) {
  return { left, right, top, bottom };
}

const { left, top } = processInput(input); // 調(diào)用者可以明確的指定需要哪個(gè)值,而且不需要?jiǎng)?chuàng)建多余的變量
數(shù)組 使用字面量賦值

eslint

no-array-constructor

// bad
const items = new Array();

// good
const items = [];
使用 .push 方法代替直接索引賦值
const items = [];

// bad
items[items.length] = "new item";

// good
items.push("new item");
使用擴(kuò)展運(yùn)算符進(jìn)行淺拷貝
const items = [1, 2, 3, 4, 5];

// bad
const length = items.length;
const copied = [];
let index;

for (index = 0; index < length; index += 1) {
  copied[index] = items[index];
}

// good
const copied = [ ...items ];
使用 ... 運(yùn)算符代替 Array.from

當(dāng)需要將一個(gè)可迭代的對(duì)象轉(zhuǎn)換成數(shù)組時(shí),推薦使用 ... 操作符。

const elements = document.querySelectorAll(".foobar");

// not bad
const nodes = Array.from(elements);

// good
const nodes = [ ...elements ];
使用 ... 解構(gòu)數(shù)組
const array = [1, 2, 3, 4, 5];

// bad
const first = array[0];
const second = array[1];

// good
const [first, second, ...rest] = array;
console.log(rest); // => [3, 4, 5]
使用 Array.from 將類(lèi)數(shù)組對(duì)象轉(zhuǎn)成數(shù)組
參考:Typed Arrays
const arrayLike = { 0: "foo", 1: "bar", 2: "baz", length: 3 }

// bad
const array = Array.prototype.slice.call(arrayLike);

// good
const array = Array.from(arrayLike);
使用 Array.from 對(duì)類(lèi)數(shù)組對(duì)象進(jìn)行遍歷
Array.from(arrayLike[, mapFn[, thisArg]]) 方法,參考 Array.from
const arrayLike = { 0: "foo", 1: "bar", 2: "baz", length: 3 }

// bad
const array = [...arrayLike].map(mapFn);

// good
const array = Array.from(arrayLike, mapFn);
在數(shù)組方法的回調(diào)函數(shù)中,永遠(yuǎn)返回正確的值
// bad - 當(dāng)?shù)谝淮蔚瓿芍螅?acc 就變成了 undefined 了
[[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
  const flatten = acc.concat(item);
  acc[index] = flatten;
});

// good
[[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
  const flatten = acc.concat(item);
  acc[index] = flatten;
  return flatten;
});

// bad
messages.filter(msg => {
  const { subject, author } = msg;
  if (subject === "ParcMG") {
    return author === "MG";
  } else {
    return false;
  }
});

// good
messages.filter(msg => {
  const { subject, author } = msg;
  if (subject === "ParcMG") {
    return author === "MG";
  }
  return false;
});

// bad
[1, 2, 3].map(x => {
  const y = x + 1;
  return x * y;
}

// good
[1, 2, 3].map(x => x * (x + 1));
一個(gè)數(shù)組有多行時(shí),在 [] 處斷行
// bad
const array = [
  [0, 1], [2, 3], [4, 5], [6, 7]
];

const objectArray = [{
  id: 1,
}, {
  id: 2,
}];

const numberArray = [
  1, 2,
];

// good
const array = [[0, 1], [2, 3], [4, 5], [6, 7]];

const objectArray = [
  {
    id: 1,
  },
  {
    id: 2,
  }
];

const numberArray = [1, 2];

const numberArray = [
  1,
  2,
];
字符串 對(duì) string 永遠(yuǎn)使用單引號(hào) ""

eslint

quotes

// bad
const name = "Parc M.G";

const name = `Parc M.G`;

// good
const name = "Parc M.G";
超長(zhǎng)的字符串,不應(yīng)該使用多行串聯(lián)
// bad
const content = "《學(xué)而》是《論語(yǔ)》第一篇的篇名?!墩撜Z(yǔ)》中各篇一般都是以第
一章的前二三個(gè)字作為該篇的篇名?!秾W(xué)而》一篇包括16章,內(nèi)容涉及諸多方面。其中重
點(diǎn)是「吾日三省吾身」;「節(jié)用而愛(ài)人,使民以時(shí)」;「禮之用,和為貴」以及仁、孝、
信等道德范疇。";

const content = "《學(xué)而》是《論語(yǔ)》第一篇的篇名?!墩撜Z(yǔ)》中各篇一般都是以第" +
"一章的前二三個(gè)字作為該篇的篇名?!秾W(xué)而》一篇包括16章,內(nèi)容涉及諸多方面。其中重" +
"點(diǎn)是「吾日三省吾身」;「節(jié)用而愛(ài)人,使民以時(shí)」;「禮之用,和為貴」以及仁、孝、" +
"信等道德范疇。";

// good
const content = "《學(xué)而》是《論語(yǔ)》第一篇的篇名。《論語(yǔ)》中各篇一般都是以第一章的前二三個(gè)字作為該篇的篇名?!秾W(xué)而》一篇包括16章,內(nèi)容涉及諸多方面。其中重點(diǎn)是「吾日三省吾身」;「節(jié)用而愛(ài)人,使民以時(shí)」;「禮之用,和為貴」以及仁、孝、信等道德范疇。";
使用模板而非拼接來(lái)組織可編程字符串

eslint

prefer-template

template-curly-spacing

// bad
function hello(name) {
  return "你好," + name + "!";
}

function hello(name) {
  return ["你好,", name, "!"].join("");
}

function hello(name) {
  return `你好,${ name }!`;
}

// good
function hello(name) {
  return `你好,${name}!`;
}
永遠(yuǎn)不使用 eval()

eslint

no-eval

若非必要,不使用轉(zhuǎn)義字符

eslint

no-useless-escape

// bad
const foo = ""this" is "quoted"";

// good
const foo = "	his" is "quoted"";

// best
const foo = `"this" is "quoted"`;
函數(shù) 使用命名函數(shù)表達(dá)式,而不是函數(shù)聲明

eslint

func-styl

使用函數(shù)聲明,它的作用域會(huì)被提前,這意味著很容易在一個(gè)文件里面引用一個(gè)還未被定義的函數(shù),這樣大大傷害了代碼的可讀性和可維護(hù)性,若一個(gè)函數(shù)很大很復(fù)雜,那么應(yīng)該考慮將該函數(shù)多帶帶提取到一個(gè)文件中,抽離成一個(gè)模塊,同時(shí)不要忘記給表達(dá)式顯示的命名,這消除了由匿名函數(shù)在錯(cuò)誤調(diào)用棧中產(chǎn)生的所有假設(shè)。
// bad
function foo() {
  // ...
}

// bad
const foo = function () {
  // ...
}

// good
const foo = function foo() {
  // ...
}

// best
const foo = function longUniqueMoreDescriptiveLexicalFoo() {
  // ...
}
把立即執(zhí)行函數(shù)包裹在圓括號(hào)里

eslint

wrap-iife

(function () {
  console.log("Welcome to the ParcMG world.");
}());
不要在非函數(shù)塊內(nèi)聲明函數(shù)

雖然運(yùn)行環(huán)境允許你這樣做,但是不同環(huán)境的解析方式不一樣。

eslint

no-loop-func

//bad 
for (var i=10; i; i--) {
    (function() { return i; })();
}

while(i) {
    var a = function() { return i; };
    a();
}

do {
    function a() { return i; };
    a();
} while (i);

let foo = 0;
for (let i = 0; i < 10; ++i) {
    // Bad, `foo` is not in the loop-block"s scope and `foo` is modified in/after the loop
    setTimeout(() => console.log(foo));
    foo += 1;
}

for (let i = 0; i < 10; ++i) {
    // Bad, `foo` is not in the loop-block"s scope and `foo` is modified in/after the loop
    setTimeout(() => console.log(foo));
}
foo = 100;

// good
var a = function() {};

for (var i=10; i; i--) {
    a();
}

for (var i=10; i; i--) {
    var a = function() {}; // OK, no references to variables in the outer scopes.
    a();
}

for (let i=10; i; i--) {
    var a = function() { return i; }; // OK, all references are referring to block scoped variables in the loop.
    a();
}

var foo = 100;
for (let i=10; i; i--) {
    var a = function() { return foo; }; // OK, all references are referring to never modified variables.
    a();
}

注意:在 ECMA-262 中,塊(block 的定義是:一系列語(yǔ)句,但函數(shù)聲明不是一個(gè)語(yǔ)句,命名函數(shù)表達(dá)式是一個(gè)語(yǔ)句。

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

// good
let test;
if (currentUser) {
  test = () => {
    console.log("Yup.");
  };
}
不允許使用 arguments 命名參數(shù)

arguments 的優(yōu)先級(jí)高于高于每個(gè)函數(shù)作用域自帶的 arguments 對(duì)象,這會(huì)導(dǎo)致函數(shù)自帶的 arguments 值被覆蓋。

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

// good
function foo(name, options, args) {
  // ...
}
不要在函數(shù)體內(nèi)使用 arguments,使用 ...rest 代替

eslint

prefer-rest-params

... 明確出你想用那個(gè)參數(shù),同時(shí),rest 是一個(gè)真數(shù)組,而不是一個(gè)類(lèi)數(shù)組的 arguments
// bad
function concatenateAll() {
  const args = Array.prototype.slice.call(arguments);
  return args.join("");
}

// good
function concatenateAll(...args) {
  return args.join("");
}
使用默認(rèn)參數(shù),而不是在函數(shù)體內(nèi)對(duì)參數(shù)重新賦值
// really bad
function handleThings(options) {
  options = options || {};
}

// still bad
function handleTings(options) {
  if (options === void 0) {
    options = {};
  }
}

// good
function handleThings(options = {}) {
}
默認(rèn)參數(shù)要避免副作用
// bad
let v = 1;
const count = function count(a = v++) {
  console.log(a);
}

count();   // => 1
count();   // => 2
count(3);  // => 3
count();   // => 3

// maybe
const v = 1;
const count = function count(a = v) {
  console.log(a);
}
把默認(rèn)參數(shù)放在最后
// bad
function handleTings(options = {}, name) {
  // ...
}

// good
function handleTings(name, options = {}) {
  // ...
}
不要使用函數(shù)構(gòu)造器構(gòu)造函數(shù)

eslint

no-new-func

// bad
var add = new Function("a", "b", "return a + b");

// still bad
var subtract = Function("a", "b", "return a - b");

// good
const subtract = (a, b) => a + b;
函數(shù)簽名部分要有空格

eslint

space-before-function-paren

space-before-blocks

// bad
const f = function(){};
const g = function (){};
const h = function() {};

// good
const f = function a() {};
不修改參數(shù)

eslint

no-param-reassign

函數(shù)簽名時(shí)定義的參數(shù),在函數(shù)體內(nèi)不允許被重新賦值(包含參數(shù)本身,若參數(shù)為對(duì)象,還包括該對(duì)象所有屬性的值),
一個(gè)函數(shù)應(yīng)該是沒(méi)有任何副作用的。
// bad
function f1 (obj) {
  obj.key = 1;
};

function f2 (a) {
  a = 1;
  // ...
}

function f3 (a) {
  if (!a) { a = 1; }
  // ...
}

// good
function f4(obj) {
  const key = Object.prototype.hasOwnProperty.call(obj, "key") ? obj.key : 1;
};

function f5(a) {
  const b = a || 1;
  // ...
}

function f6(a = 1) {
  // ...
}
使用 spread 操作符 ... 調(diào)用多變參數(shù)函數(shù)

eslint

prefer-spread

// bad
const x = [1, 2, 3, 4, 5];
console.log.apply(console, x);

// good
const x = [1, 2, 3, 4, 5];
console.log(...x);

// bad
new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));

// good
new Date(...[2016, 8, 5]);
若函數(shù)簽名包含多個(gè)參數(shù)需要使用多行,那就每行有且僅有一個(gè)參數(shù)
// bad
function foo(bar,
             baz,
             quux) {
  // ...
}

// good 縮進(jìn)不要太過(guò)分
function foo(
  bar,
  baz,
  quux,
) {
  // ...
}

// bad
console.log(foo,
  bar,
  baz);

// good
console.log(
  foo,
  bar,
  baz,
);
箭頭函數(shù) 當(dāng)你一定要用函數(shù)表達(dá)式的時(shí)候,就使用箭頭函數(shù)

eslint

prefer-array-callback

arrow-spacing

// bad
[1, 2, 3].map(function (x) {
  const y = x + 1;
  return x * y;
});

// good
[1, 2, 3].map((x) => {
  const y = x + 1;
  return x * y;
});
如果函數(shù)體有且僅有一個(gè)沒(méi)有副作用的表達(dá)式,那么刪除大括號(hào)和 return

eslint

arrow-parens

arrow-body-style

// bad
[1, 2, 3].map(number => {
  const nextNumber = number + 1;
  `A string containing the ${nextNumber}.`;
});

// good
[1, 2, 3].map(number => `A string containing the ${number}.`);

// good
[1, 2, 3].map((number) => {
  const nextNumber = number + 1;
  return `A string containing the ${nextNumber}.`;
});

// good
[1, 2, 3].map((number, index) => ({
  [index]: number
}));

// 表達(dá)式有副作用就不要用隱式return
function foo(callback) {
  const val = callback();
  if (val === true) {
    // Do something if callback returns true
  }
}

let bool = false;

// bad
// 這種情況會(huì)return bool = true, 不好
foo(() => bool = true);

// good
foo(() => {
  bool = true;
});
若表達(dá)式包含多行,用圓括號(hào)包裹起來(lái)
// bad
["get", "post", "put"].map(httpMethod => Object.prototype.hasOwnProperty.call(
    httpMagicObjectWithAVeryLongName,
    httpMethod
  )
);

// good
["get", "post", "put"].map(httpMethod => (
  Object.prototype.hasOwnProperty.call(
    httpMagicObjectWithAVeryLongName,
    httpMethod
  )
));
若函數(shù)只有一個(gè)參數(shù),且沒(méi)有大括號(hào),那就刪除圓括號(hào),否則,參數(shù)總是放在圓括號(hào)里。

eslint

arrow-parens

// bad
[1, 2, 3].map((x) => x * x);

// good
[1, 2, 3].map(x => x * x);

// good
[1, 2, 3].map(number => (
  `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
));

// bad
[1, 2, 3].map(x => {
  const y = x + 1;
  return x * y;
});

// good
[1, 2, 3].map((x) => {
  const y = x + 1;
  return x * y;
});
避免箭頭函數(shù)(=>)和比較操作符(<=, >=)混淆.

eslint

no-confusing-arrow

// bad
const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize;

// bad
const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize;

// good
const itemHeight = item => (item.height > 256 ? item.largeSize : item.smallSize);

// good
const itemHeight = (item) => {
  const { height, largeSize, smallSize } = item;
  return height > 256 ? largeSize : smallSize;
};
在隱式return中強(qiáng)制約束函數(shù)體的位置, 就寫(xiě)在箭頭后面

eslint

implicit-arrow-linebreak

// bad
(foo) =>
  bar;

(foo) =>
  (bar);

// good
(foo) => bar;
(foo) => (bar);
(foo) => (
   bar
)
類(lèi)與構(gòu)造器 使用構(gòu)造器,而不是 prototype
// bad
function Queue(contents = []) {
  this.queue = [...contents];
}
Queue.prototype.pop = function () {
  const value = this.queue[0];
  this.queue.splice(0, 1);
  return value;
};


// good
class Queue {
  constructor(contents = []) {
    this.queue = [...contents];
  }
  pop() {
    const value = this.queue[0];
    this.queue.splice(0, 1);
    return value;
  }
}
使用 extends 實(shí)現(xiàn)繼承

它是一種內(nèi)置的方法來(lái)繼承原型功能而不打破 instanceof

// bad
const inherits = require("inherits");
function PeekableQueue(contents) {
  Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
  return this._queue[0];
}

// good
class PeekableQueue extends Queue {
  peek() {
    return this._queue[0];
  }
}
方法可以返回 this 實(shí)現(xiàn)方法鏈
// bad
Jedi.prototype.jump = function () {
  this.jumping = true;
  return true;
};

Jedi.prototype.setHeight = function (height) {
  this.height = height;
};

const luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20); // => undefined

// good
class Jedi {
  jump() {
    this.jumping = true;
    return this;
  }

  setHeight(height) {
    this.height = height;
    return this;
  }
}

const luke = new Jedi();

luke.jump()
  .setHeight(20);
只要保證可以正常工作且沒(méi)有副作用,可以自已定制 toString 方法
class Jedi {
  constructor(options = {}) {
    this.name = options.name || "no name";
  }

  getName() {
    return this.name;
  }

  toString() {
    return `Jedi - ${this.getName()}`;
  }
}
不要寫(xiě)無(wú)用的構(gòu)造函數(shù)

eslint

no-useless-constructor

// bad
class Jedi {
  constructor() {}

  getName() {
    return this.name;
  }
}

// bad
class Rey extends Jedi {
  // 這種構(gòu)造函數(shù)是不需要寫(xiě)的
  constructor(...args) {
    super(...args);
  }
}

// good
class Rey extends Jedi {
  constructor(...args) {
    super(...args);
    this.name = "Rey";
  }
}
避免重復(fù)類(lèi)成員

eslint

no-dupe-class-members

// bad
class Foo {
  bar() { return 1; }
  bar() { return 2; }
}

// good
class Foo {
  bar() { return 1; }
}

// good
class Foo {
  bar() { return 2; }
}
模塊 使用 import / export
// bad
const Button = require("./Button");
module.exports = Button.es6;

// ok
import Button from "./Button";
export default Button.es6;

// best
import { es6 } from "./Button";
export default es6;
不要 import 通配符
// bad
import * as Component from "./Component";

// good
import Component from "./Component";
不要直接從 importexport
雖然一行是簡(jiǎn)潔的,有一個(gè)明確的方式進(jìn)口和一個(gè)明確的出口方式來(lái)保證一致性。
// bad
export { es6 as default } from "./Component";

// good
import { es6 } from "./Component";
export default es6;
一個(gè)路徑只 import 一次

eslint

no-duplicate-imports

從同一個(gè)路徑下import多行會(huì)使代碼難以維護(hù)
// bad
import foo from "foo";
// … some other imports … //
import { named1, named2 } from "foo";

// good
import foo, { named1, named2 } from "foo";

// good
import foo, {
  named1,
  named2,
} from "foo";
若非必要,不要 export 可變量

eslint

import/no-mutable-exports

變化通常都是需要避免,特別是當(dāng)你要輸出可變的綁定。雖然在某些場(chǎng)景下可能需要這種技術(shù),但總的來(lái)說(shuō)應(yīng)該導(dǎo)出常量。
// bad
let foo = 3;
export { foo }

// good
const foo = 3;
export { foo }
在一個(gè)單一導(dǎo)出模塊里,使用 export default

eslint

import/prefer-default-export

鼓勵(lì)使用更多文件,每個(gè)文件只做一件事情并導(dǎo)出,這樣可讀性和可維護(hù)性更好。
// bad
export function foo() {}

// good
export default function foo() {}
import 應(yīng)該放在所有其它語(yǔ)句之前

eslint

import/first

// bad
import foo from "foo";
foo.init();

import bar from "bar";

// good
import foo from "foo";
import bar from "bar";

foo.init();
多行import應(yīng)該縮進(jìn),就像多行數(shù)組和對(duì)象字面量
花括號(hào)與樣式指南中每個(gè)其他花括號(hào)塊遵循相同的縮進(jìn)規(guī)則,逗號(hào)也是。
// bad
import {longNameA, longNameB, longNameC, longNameD, longNameE} from "path";

// good
import {
  longNameA,
  longNameB,
  longNameC,
  longNameD,
  longNameE,
} from "path";
若使用 webpack,不允許在 import 中使用 webpack loader 語(yǔ)法

eslint

import/no-webpack-loader-syntax

一旦用 Webpack 語(yǔ)法在 import 里會(huì)把代碼耦合到模塊綁定器。最好是在 webpack.config.js 里寫(xiě) webpack loader 語(yǔ)法
// bad
import fooSass from "css!sass!foo.scss";
import barCss from "style!css!bar.css";

// good
import fooSass from "foo.scss";
import barCss from "bar.css";
迭代器與生成器 不要使用遍歷器

eslint

no-iterator

no-restricted-syntax

用JavaScript高級(jí)函數(shù)代替 for-in、for-of

這強(qiáng)調(diào)了我們不可變的規(guī)則。 處理返回值的純函數(shù)比副作用更容易。

用數(shù)組的這些迭代方法: map()every()、filter()、find()findIndex()、reduce()、some()……

用對(duì)象的這些方法 Object.keys()Object.values()、Object.entries 去產(chǎn)生一個(gè)數(shù)組, 這樣你就能去遍歷對(duì)象了。

const numbers = [1, 2, 3, 4, 5];

// bad
let sum = 0;
for (let num of numbers) {
  sum += num;
}
sum === 15;

// good
let sum = 0;
numbers.forEach(num => sum += num);
sum === 15;

// best (use the functional force)
const sum = numbers.reduce((total, num) => total + num, 0);
sum === 15;

// bad
const increasedByOne = [];
for (let i = 0; i < numbers.length; i++) {
  increasedByOne.push(numbers[i] + 1);
}

// good
const increasedByOne = [];
numbers.forEach(num => increasedByOne.push(num + 1));

// best (keeping it functional)
const increasedByOne = numbers.map(num => num + 1);
不要用 generator

eslint

generator-star-spacing

它在es5上支持的不好

如果一定要用,那么一定需要注意一點(diǎn):function* 是同一概念關(guān)鍵字, * 并不是 function 的修飾符, function* 是一個(gè)與 function 完全不一樣的獨(dú)特結(jié)構(gòu)。

// bad
function * foo() {
  // ...
}

// bad
const bar = function * () {
  // ...
}

// bad
const baz = function *() {
  // ...
}

// bad
const quux = function*() {
  // ...
}

// bad
function*foo() {
  // ...
}

// bad
function *foo() {
  // ...
}

// very bad
function
*
foo() {
  // ...
}

// very bad
const wat = function
*
() {
  // ...
}

// good
function* foo() {
  // ...
}

// good
const foo = function* () {
  // ...
}
屬性 訪問(wèn)屬性使用 . 號(hào)

eslint

dot-notation

這條,涉及一個(gè)曾經(jīng)阿里出過(guò)一個(gè)看似簡(jiǎn)單,實(shí)則很難的面試題,你就算猜對(duì)一個(gè),你也不一定能說(shuō)出原理:

a.b.c.d和a"b"["d"],哪個(gè)性能更高

到這里,突然想起這個(gè)梗,有興趣的可以翻看一下 這里。

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

// bad
const isJedi = luke["jedi"];

// good
const isJedi = luke.jedi;
當(dāng)獲取屬性名稱(chēng)本身是一個(gè)變量是,使用 [] 訪問(wèn)
const luke = {
  jedi: true,
  age: 28,
};

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

const isJedi = getProp("jedi");
冪等使用 ** 操作符

eslint

no-restricted-properties

// bad
const binary = Math.pow(2, 10);

// good
const binary = 2 ** 10;
變量 永遠(yuǎn)使用 const 或者 let,不使用 var

eslint

no-undef

prefer-const

// bad
superPower = new SuperPower();

// good
const superPower = new SuperPower();
每一個(gè)變量都用一個(gè) const 或者 let

eslint

one-var

扯蛋的理由:這種方式很容易去聲明新的變量,你不用去考慮把;調(diào)換成,,或者引入一個(gè)只有標(biāo)點(diǎn)的不同的變化。

真正的理由:做法也可以是你在調(diào)試的時(shí)候單步每個(gè)聲明語(yǔ)句,而不是一下跳過(guò)所有聲明。

// bad
const items = getItems(),
    goSportsTeam = true,
    dragonball = "z";

const items = getItems(),
    goSportsTeam = true;
    dragonball = "z";

// good
const items = getItems();
const goSportsTeam = true;
const dragonball = "z";
塵歸塵,土歸土

在同一個(gè)塊中,所有的 const 放在一起,所有的 let 放在一起

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

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

// good
const goSportsTeam = true;
const items = getItems();
let dragonball;
let i;
let length;
在你需要的地方聲明變量,但要放在合理的位置
// bad
function checkName(hasName) {
  const name = getName();

  if (hasName === "test") {
    return false;
  }

  if (name === "test") {
    this.setName("");
    return false;
  }

  return name;
}

// good
function checkName(hasName) {
  if (hasName === "test") {
    return false;
  }

  // 在需要的時(shí)候分配
  const name = getName();

  if (name === "test") {
    this.setName("");
    return false;
  }

  return name;
}
不使用鏈接變量分配

eslint

no-multi-assign

鏈接變量分配會(huì)隱匿創(chuàng)建全局變量

// bad
(function example() {
  // JavaScript 將這一段解釋為
  // let a = ( b = ( c = 1 ) );
  // let 只對(duì)變量 a 起作用; 變量 b 和 c 都變成了全局變量
  let a = b = c = 1;
}());

console.log(a); // undefined
console.log(b); // 1
console.log(c); // 1

// good
(function example() {
  let a = 1;
  let b = a;
  let c = a;
}());

console.log(a); // undefined
console.log(b); // undefined
console.log(c); // undefined

// `const` 也是如此
不使用一元自增自減運(yùn)算(++、--

eslint

no-plusplus

根據(jù) eslint 文檔,一元增量和減量語(yǔ)句受到自動(dòng)分號(hào)插入的影響,并且可能會(huì)導(dǎo)致應(yīng)用程序中的值遞增或遞減的無(wú)聲錯(cuò)誤。 使用 num + = 1 而不是 num ++num ++ 語(yǔ)句來(lái)表達(dá)你的值也是更有表現(xiàn)力的。 禁止一元增量和減量語(yǔ)句還會(huì)阻止您無(wú)意地預(yù)增/預(yù)減值,這也會(huì)導(dǎo)致程序出現(xiàn)意外行為。

// bad

let array = [1, 2, 3];
let num = 1;
num++;
--num;

let sum = 0;
let truthyCount = 0;
for(let i = 0; i < array.length; i++){
  let value = array[i];
  sum += value;
  if (value) {
    truthyCount++;
  }
}

// good

let array = [1, 2, 3];
let num = 1;
num += 1;
num -= 1;

const sum = array.reduce((a, b) => a + b, 0);
const truthyCount = array.filter(Boolean).length;
賦值時(shí)不換行

eslint

operator-linebreak

如果賦值語(yǔ)句超出了 max-len 配置,那么給值前面加上括號(hào)。

// bad
const foo =
  superLongLongLongLongLongLongLongLongFunctionName();

// bad
const foo
  = "superLongLongLongLongLongLongLongLongString";

// good
const foo = (
  superLongLongLongLongLongLongLongLongFunctionName()
);

// good
const foo = "superLongLongLongLongLongLongLongLongString";
不允許聲明不使用的變量

eslint

no-unused-vars

// bad

var some_unused_var = 42;

// 寫(xiě)了沒(méi)用
var y = 10;
y = 5;

// 變量改了自己的值,也沒(méi)有用這個(gè)變量
var z = 0;
z = z + 1;

// 參數(shù)定義了但未使用
function getX(x, y) {
    return x;
}

// good
function getXPlusY(x, y) {
  return x + y;
}

var x = 1;
var y = a + 2;

alert(getXPlusY(x, y));

// "type" 即使沒(méi)有使用也可以可以被忽略, 因?yàn)檫@個(gè)有一個(gè) rest 取值的屬性。
// 這是從對(duì)象中抽取一個(gè)忽略特殊字段的對(duì)象的一種形式
var { type, ...coords } = data;
// "coords" 現(xiàn)在就是一個(gè)沒(méi)有 "type" 屬性的 "data" 對(duì)象
變量提升 永遠(yuǎn)不要使用 var

var 聲明會(huì)將變量聲明提升到作用域的最前面,但是他的值卻只有在運(yùn)行到代碼行時(shí)才會(huì)被賦值,永遠(yuǎn)都使用 constlet,了解 時(shí)效區(qū)(Temporal Dead Zones) 的相關(guān)知識(shí),也還要知道為什么 typeof 不再安全。

// 我們知道這個(gè)不會(huì)工作,假設(shè)沒(méi)有定義全局的notDefined
function example() {
  console.log(notDefined); // => throws a ReferenceError
}

// 在你引用的地方之后聲明一個(gè)變量,他會(huì)正常輸出是因?yàn)樽兞孔饔糜蛏仙?// 注意: declaredButNotAssigned的值沒(méi)有上升
function example() {
  console.log(declaredButNotAssigned); // => undefined
  var declaredButNotAssigned = true;
}

// 解釋器把變量聲明提升到作用域最前面,
// 可以重寫(xiě)成如下例子, 二者意義相同
function example() {
  let declaredButNotAssigned;
  console.log(declaredButNotAssigned); // => undefined
  declaredButNotAssigned = true;
}

// 用 const, let就不一樣了
function example() {
  console.log(declaredButNotAssigned); // => throws a ReferenceError
  console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
  const declaredButNotAssigned = true;
}
匿名函數(shù)表達(dá)式與 var 的情況一樣
function example() {
  console.log(anonymous); // => undefined

  anonymous(); // => TypeError anonymous is not a function

  var anonymous = function () {
    console.log("anonymous function expression");
  };
}
已命名函數(shù)表達(dá)式只提升變量名,而不是函數(shù)名或者函數(shù)體
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");
  };
}

// 函數(shù)名和變量名一樣是也如此
function example() {
  console.log(named); // => undefined

  named(); // => TypeError named is not a function

  var named = function named() {
    console.log("named");
  };
}
函數(shù)聲明則提升了函數(shù)名和函數(shù)體
function example() {
  superPower(); // => Flying

  function superPower() {
    console.log("Flying");
  }
}
比較操作符 永遠(yuǎn)使用 ===!==,而不是 ==!=

eslint

eqeqeq

if 條件語(yǔ)句的強(qiáng)制 toBoolean

if 條件語(yǔ)句的強(qiáng)制 toBoolean 總是遵循以下規(guī)則:

Objects 總是計(jì)算成 true

Undefined 總是計(jì)算 成 false

Null 總是計(jì)算成 false

Booleans 計(jì)算成它本身的布爾值

Numbers

+0、-0 或者 NaN 總是計(jì)算成 false

其它的全部為 true

Strings

"" 計(jì)算成 false

其它全部為 true

注意NaN 是不等于 NaN 的,請(qǐng)使用 isNaN() 檢測(cè)。
if ([0] && []) {
  // true
  // 數(shù)組(即使是空數(shù)組)是對(duì)象,對(duì)象會(huì)計(jì)算成true
}

console.log(NaN === NaN) // => false
console.log(isNaN(NaN))  // => true
布爾值要使用縮寫(xiě),但是字符串與數(shù)字要明確比較對(duì)象
// bad
if (isValid === true) {
  // ...
}

// good
if (isValid) {
  // ...
}

// bad
if (name) {
  // ...
}

// good
if (name !== "") {
  // ...
}

// bad
if (collection.length) {
  // ...
}

// good
if (collection.length > 0) {
  // ...
}
switchcasedefault 分句中使用大括號(hào)創(chuàng)建語(yǔ)法聲明區(qū)域

eslint

no-case-declarations

語(yǔ)法聲明在整個(gè) switch 的代碼塊里都可見(jiàn),但是只有當(dāng)其被分配后才會(huì)初始化,他的初始化時(shí)當(dāng)這個(gè) case 被執(zhí)行時(shí)才產(chǎn)生。 當(dāng)多個(gè) case 分句試圖定義同一個(gè)事情時(shí)就出問(wèn)題了

// bad
switch (foo) {
  case 1:
    let x = 1;
    break;
  case 2:
    const y = 2;
    break;
  case 3:
    function f() {
      // ...
    }
    break;
  default:
    class C {}
}

// good
switch (foo) {
  case 1: {
    let x = 1;
    break;
  }
  case 2: {
    const y = 2;
    break;
  }
  case 3: {
    function f() {
      // ...
    }
    break;
  }
  case 4:
    bar();
    break;
  default: {
    class C {}
  }
}
三元運(yùn)算符不能被嵌套

eslint

no-nested-ternary

// bad
const foo = maybe1 > maybe2
  ? "bar"
  : value1 > value2 ? "baz" : null;

// better
const maybeNull = value1 > value2 ? "baz" : null;

const foo = maybe1 > maybe2
  ? "bar"
  : maybeNull;

// best
const maybeNull = value1 > value2 ? "baz" : null;

const foo = maybe1 > maybe2 ? "bar" : maybeNull;
避免不必要的三元表達(dá)式
// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;

// good
const foo = a || b;
const bar = !!c;
const baz = !c;
除非優(yōu)先級(jí)顯而易見(jiàn),否則使用圓括號(hào)來(lái)混合操作符

eslint

no-mixed-operators

開(kāi)發(fā)者需要以最顯而易見(jiàn)的方式明確自己的意圖與邏輯

// bad
const foo = a && b < 0 || c > 0 || d + 1 === 0;

// bad
const bar = a ** b - 5 % d;

// bad
// 別人會(huì)陷入(a || b) && c 的迷惑中
if (a || b && c) {
  return d;
}

// good
const foo = (a && b < 0) || c > 0 || (d + 1 === 0);

// good
const bar = (a ** b) - (5 % d);

// good
if (a || (b && c)) {
  return d;
}

// good
const bar = a + b / c * d;
區(qū)塊 用大括號(hào)包裹多行代碼

eslint

nonblock-statement-body-position

// bad
if (test)
  return false;

// good
if (test) return false;

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

// bad
function foo() { return false; }

// good
function bar() {
  return false;
}
if 以及 elseif 的關(guān)閉大括號(hào)在同一行

eslint

brace-style

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

// good
if (test) {
  thing1();
  thing2();
} else {
  thing3();
}
if 語(yǔ)句中的 return

eslint

no-else-return

如果 if 語(yǔ)句中總是需要用 return 返回,那么后續(xù)的 else 就不需要寫(xiě)了

如果 if 塊中包含 return,它后面的 else if 也包含了 return,那就應(yīng)該把 else ifreturn 分到多個(gè) if 語(yǔ)句塊中去。

// bad
function foo() {
  if (x) {
    return x;
  } else {
    return y;
  }
}

// bad
function cats() {
  if (x) {
    return x;
  } else if (y) {
    return y;
  }
}

// bad
function dogs() {
  if (x) {
    return x;
  } else {
    if (y) {
      return y;
    }
  }
}

// good
function foo() {
  if (x) {
    return x;
  }

  return y;
}

// good
function cats() {
  if (x) {
    return x;
  }

  if (y) {
    return y;
  }
}

// good
function dogs(x) {
  if (x) {
    if (z) {
      return y;
    }
  } else {
    return z;
  }
}
控制語(yǔ)句 當(dāng)你的控制語(yǔ)句 (ifwhile)等太長(zhǎng),或者超過(guò)最大長(zhǎng)度限制時(shí),把每一個(gè)判斷條件都放到多帶帶一行去,邏輯操作符放在行首
// bad
if ((foo === 123 || bar === "abc") && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
  thing1();
}

// bad
if (foo === 123 &&
  bar === "abc") {
  thing1();
}

// bad
if (foo === 123
  && bar === "abc") {
  thing1();
}

// bad
if (
  foo === 123 &&
  bar === "abc"
) {
  thing1();
}

// good
if (
  foo === 123
  && bar === "abc"
) {
  thing1();
}

// good
if (
  (foo === 123 || bar === "abc")
  && doesItLookGoodWhenItBecomesThatLong()
  && isThisReallyHappening()
) {
  thing1();
}

// good
if (foo === 123 && bar === "abc") {
  thing1();
}
不要用選擇操作符代替控制語(yǔ)句
// bad
!isRunning && startRunning();

// good
if (!isRunning) {
  startRunning();
}
注釋 多行注釋使用 /** ... */
// bad
// make() 基于傳入的 `tag` 名返回一個(gè)新元素
//
// @param {String} 標(biāo)簽名
// @return {Element} 新元素
function make(tag) {

  // ...

  return element;
}

// good
/**
 * make() 基于傳入的 `tag` 名返回一個(gè)新元素
 * @param {String} 標(biāo)簽名
 * @param {Element} 新元素
 */
function make(tag) {

  // ...

  return element;
}
單行注釋用 //

將單行注釋放在被注釋區(qū)域上面。如果注釋不是在第一行,那么注釋前面就空一行

// bad
const active = true;  // is current tab

// good
// 當(dāng)前激活狀態(tài)的 tab
const active = true;

// bad
function getType() {
  console.log("fetching type...");
  // 設(shè)置默認(rèn) `type` 為 "no type"
  const type = this._type || "no type";

  return type;
}

// good
function getType() {
  console.log("fetching type...");

  // 設(shè)置默認(rèn) `type` 為 "no type"
  const type = this._type || "no type";

  return type;
}

// also good
function getType() {
  // 設(shè)置默認(rèn) `type` 為 "no type"
  const type = this._type || "no type";

  return type;
}
所有注釋開(kāi)頭空一個(gè),方便閱讀

eslint

space-comment

// bad
//當(dāng)前激活的 tab
const active = true;

// good
// 當(dāng)前激活的 tab
const active = true;

// bad
/**
 *make() 基于傳入的 `tag` 名返回一個(gè)新元素
 *@param {String} 標(biāo)簽名
 *@param {Element} 新元素
 */
function make(tag) {

  // ...

  return element;
}

// good
/**
 * make() 基于傳入的 `tag` 名返回一個(gè)新元素
 * @param {String} 標(biāo)簽名
 * @param {Element} 新元素
 */
function make(tag) {

  // ...

  return element;
}
積極使用 FIXMETODO

當(dāng)你的注釋需要向注釋閱讀者或者代碼的后繼開(kāi)發(fā)者明確的表述一種期望時(shí),應(yīng)該積極使用 FIXME 以及 TODO 前綴,這有助于其他的開(kāi)發(fā)理解你指出的需要重新訪問(wèn)的問(wèn)題,也方便自己日后有時(shí)間的時(shí)候再次回顧當(dāng)時(shí)沒(méi)有解決或者計(jì)劃去做而沒(méi)有做的事情。

FIXME:這里有一個(gè)問(wèn)題,現(xiàn)在還沒(méi)有影響大局,但是更希望解決這個(gè)問(wèn)題或者找到一個(gè)更優(yōu)雅的方式去實(shí)現(xiàn)

TODO:計(jì)劃在這里去實(shí)現(xiàn)某些功能,現(xiàn)在還沒(méi)有實(shí)現(xiàn)

// 使用 FIXME: 
class Calculator extends Abacus {
  constructor() {
    super();

    // FIXME: 不應(yīng)該在此處使用全局變量
    total = 0;
  }
}

// 使用 TODO: 
class Calculator extends Abacus {
  constructor() {
    super();

    // TODO: total 應(yīng)該應(yīng)該從一個(gè)參數(shù)中獲取并初始化
    this.total = 0;
  }
}
空格 代碼縮進(jìn)總是使用兩個(gè)空格

eslint

indent

// bad
function foo() {
????const name;
}

// bad
function bar() {
?const name;
}

// good
function baz() {
??const name;
}
在大括號(hào)前空一格

eslint

space-before-blocks

// 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",
});
關(guān)鍵字空格

eslint

keyword-spacing

在控制語(yǔ)句( if, while 等)的圓括號(hào)前空一格。在函數(shù)調(diào)用和定義時(shí),參數(shù)列表和函數(shù)名之間不空格。

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

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

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

// good
function fight() {
  console.log("Swooosh!");
}
用空格來(lái)隔開(kāi)運(yùn)算符

eslint

space-infix-ops

// bad
const x=y+5;

// good
const x = y + 5;
文件結(jié)尾加一個(gè)換行

eslint

eol-last

// bad
function doSmth() {
  var foo = 2;
}
// good
function doSmth() {
  var foo = 2;
}
使用多行縮進(jìn)的方式進(jìn)行一個(gè)長(zhǎng)方法鏈調(diào)用

eslint

newline-per-chained-call

no-whitespace-before-property

// 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
const 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
const 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
const leds = stage.selectAll(".led").data(data);
在一個(gè)代碼塊后下一條語(yǔ)句前空一行
// bad
if (foo) {
  return bar;
}
return baz;

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

return baz;

// bad
const obj = {
  foo() {
  },
  bar() {
  },
};
return obj;

// good
const obj = {
  foo() {
  },

  bar() {
  },
};

return obj;

// bad
const arr = [
  function foo() {
  },
  function bar() {
  },
];
return arr;

// good
const arr = [
  function foo() {
  },

  function bar() {
  },
];

return arr;
不要用空白行填充塊

eslint

padded-blocks

// bad
function bar() {

  console.log(foo);

}

// also bad
if (baz) {

  console.log(qux);
} else {
  console.log(foo);

}

// good
function bar() {
  console.log(foo);
}

// good
if (baz) {
  console.log(qux);
} else {
  console.log(foo);
}
圓括號(hào)里不加空格

eslint

space-in-parens

// bad
function bar( foo ) {
  return foo;
}

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

// bad
if ( foo ) {
  console.log(foo);
}

// good
if (foo) {
  console.log(foo);
}
方括號(hào)里,首尾都不要加空格與元素分隔

eslint

array-bracket-spacing

// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);

// good, 逗號(hào)分隔符還是要空格的
const foo = [1, 2, 3];
console.log(foo[0]);
花括號(hào)里要加空格

eslint

object-curly-spacing

// bad
const foo = {clark: "kent"};

// good
const foo = { clark: "kent" };
避免一行代碼超過(guò)100個(gè)字符(包含空格)

eslint

max-len

為了確保代碼的人類(lèi)可讀性與可維護(hù)性,代碼行應(yīng)避免超過(guò)一定的長(zhǎng)度

// bad
const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy;

// bad
$.ajax({ method: "POST", url: "https://parcmg.com/", data: { name: "John" } }).done(() => console.log("Congratulations!")).fail(() => console.log("You have failed this city."));

// good
const foo = jsonData
  && jsonData.foo
  && jsonData.foo.bar
  && jsonData.foo.bar.baz
  && jsonData.foo.bar.baz.quux
  && jsonData.foo.bar.baz.quux.xyzzy;

// good
$.ajax({
  method: "POST",
  url: "https://apis.parcmg.com/",
  data: { name: "John" },
})
  .done(() => console.log("Congratulations!"))
  .fail(() => console.log("You have failed this city."));
作為語(yǔ)句的花括號(hào)里不應(yīng)該加空格

eslint

block-spacing

// bad
function foo() {return true;}
if (foo) { bar = 0;}

// good
function foo() { return true; }
if (foo) { bar = 0; }
, 前不要空格,,后需要空格

eslint

comma-spacing

// bad
var foo = 1,bar = 2;
var arr = [1 , 2];

// good
var foo = 1, bar = 2;
var arr = [1, 2];
計(jì)算屬性內(nèi)要空格

eslint

computed-property-spacing

// bad
obj[foo ]
obj[ "foo"]
var x = {[ b ]: a}
obj[foo[ bar ]]

// good
obj[foo]
obj["foo"]
var x = { [b]: a }
obj[foo[bar]]
調(diào)用函數(shù)時(shí),函數(shù)名和小括號(hào)之間不要空格

eslint

func-call-spacing

// bad
func ();

func
();

// good
func();
在對(duì)象的字面量屬性中, keyvalue 之間要有空格

eslint

key-spacing

// bad
var obj = { "foo" : 42 };
var obj2 = { "foo":42 };

// good
var obj = { "foo": 42 };
行末不要空格

eslint

no-trailing-spaces

避免出現(xiàn)連續(xù)多個(gè)空行,文件末尾只允許空一行

eslint

no-multiple-empty-lines

// bad
var x = 1;



var y = 2;

// good
var x = 1;

var y = 2;
逗號(hào) 不要前置逗號(hào)

eslint

comma-style

// bad
const story = [
    once
  , upon
  , aTime
];

// good
const story = [
  once,
  upon,
  aTime,
];

// bad
const hero = {
    firstName: "Ada"
  , lastName: "Lovelace"
  , birthYear: 1815
  , superPower: "computers"
};

// good
const hero = {
  firstName: "Ada",
  lastName: "Lovelace",
  birthYear: 1815,
  superPower: "computers",
};
額外結(jié)尾逗號(hào)

eslint

comma-dangle

就算項(xiàng)目有可能運(yùn)行在舊版本的瀏覽器中,但是像 Babel 這樣的轉(zhuǎn)換器都會(huì)在轉(zhuǎn)換代碼的過(guò)程中刪除這些多余逗號(hào),所以,大膽使用它,完全不會(huì)有副作用產(chǎn)生,相反的,他能讓我們更方便的給對(duì)象或者多行數(shù)組增加、刪除屬性或者元素,同時(shí),還能讓我們的 git diffs 更清潔。
// bad - 沒(méi)有結(jié)尾逗號(hào)的 git diff
const hero = {
     firstName: "Florence",
-    lastName: "Nightingale"
+    lastName: "Nightingale",
+    inventorOf: ["coxcomb chart", "modern nursing"]
};

// good - 有結(jié)尾逗號(hào)的 git diff
const hero = {
     firstName: "Florence",
     lastName: "Nightingale",
+    inventorOf: ["coxcomb chart", "modern nursing"],
};
// bad
const hero = {
  firstName: "Dana",
  lastName: "Scully"
};

const heroes = [
  "Batman",
  "Superman"
];

// good
const hero = {
  firstName: "Dana",
  lastName: "Scully",
};

const heroes = [
  "Batman",
  "Superman",
];

// bad
function createHero(
  firstName,
  lastName,
  inventorOf
) {
  // does nothing
}

// good
function createHero(
  firstName,
  lastName,
  inventorOf,
) {
  // does nothing
}

// good (在一個(gè) "rest" 元素后面,絕對(duì)不能出現(xiàn)逗號(hào))
function createHero(
  firstName,
  lastName,
  inventorOf,
  ...heroArgs
) {
  // does nothing
}

// bad
createHero(
  firstName,
  lastName,
  inventorOf
);

// good
createHero(
  firstName,
  lastName,
  inventorOf,
);

// good (在一個(gè) "rest" 元素后面,絕對(duì)不能出現(xiàn)逗號(hào))
createHero(
  firstName,
  lastName,
  inventorOf,
  ...heroArgs
)
分號(hào) 永遠(yuǎn)明確的使用分號(hào)結(jié)束你的代碼行

eslint

semi

當(dāng) JavaScript 遇到?jīng)]有分號(hào)結(jié)尾的一行,它會(huì)執(zhí)行 自動(dòng)插入分號(hào) Automatic Semicolon Insertion 這一規(guī)則來(lái)決定行末是否加分號(hào)。如果JavaScript在你的斷行里錯(cuò)誤的插入了分號(hào),就會(huì)出現(xiàn)一些古怪的行為。當(dāng)新的功能加到JavaScript里后, 這些規(guī)則會(huì)變得更復(fù)雜難懂。顯示的結(jié)束語(yǔ)句,并通過(guò)配置代碼檢查去捕獲沒(méi)有帶分號(hào)的地方可以幫助你防止這種錯(cuò)誤。
// bad
(function () {
  const name = "Skywalker"
  return name
})()

// good
(function () {
  const name = "Skywalker";
  return name;
}());

// good, 行首加分號(hào),避免文件被連接到一起時(shí)立即執(zhí)行函數(shù)被當(dāng)做變量來(lái)執(zhí)行。
;(() => {
  const name = "Skywalker";
  return name;
}());
強(qiáng)類(lèi)型轉(zhuǎn)換 在語(yǔ)句開(kāi)始執(zhí)行強(qiáng)制類(lèi)型轉(zhuǎn)換 使用 String 進(jìn)行字符類(lèi)型轉(zhuǎn)換

eslint

no-new-wrappers

// => this.reviewScore = 9;

// bad
const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string"

// bad
const totalScore = this.reviewScore + ""; // invokes this.reviewScore.valueOf()

// bad
const totalScore = this.reviewScore.toString(); // 不保證返回string

// good
const totalScore = String(this.reviewScore);
使用 Number 進(jìn)行數(shù)字類(lèi)型轉(zhuǎn)換

eslint

radix

使用 parseInt 轉(zhuǎn)換 string 通常都需要帶上基數(shù)。

const inputValue = "4";

// bad
const val = new Number(inputValue);

// bad
const val = +inputValue;

// bad
const val = inputValue >> 0;

// bad
const val = parseInt(inputValue);

// good
const val = Number(inputValue);

// good
const val = parseInt(inputValue, 10);
在注釋中說(shuō)明為什么要使用移位運(yùn)算

如果你感覺(jué) parseInt 滿足不要你的需求,想使用移位進(jìn)行運(yùn)算,那么你一定要寫(xiě)明白,這是因?yàn)?性能問(wèn)題,同時(shí),你還需要注意,數(shù)字使用 64 位 表示的,但移位運(yùn)算常常返回的是 32 位的整形,移位運(yùn)算對(duì)于大于 32 位的整數(shù)會(huì)導(dǎo)致一些 意外行為,最大的32位整數(shù)是 2,147,483,647

// good
/**
 * parseInt是代碼運(yùn)行慢的原因
 * 用Bitshifting將字符串轉(zhuǎn)成數(shù)字使代碼運(yùn)行效率大幅增長(zhǎng)
 */
const val = inputValue >> 0;

2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647
布爾
const age = 0;

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

// good
const hasAge = Boolean(age);

// best
const hasAge = !!age;
命名規(guī)則 避免使用一個(gè)字母命名

eslint

id-length

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

// good
function query() {
  // ...
}
使用小駝峰式命名對(duì)象、函數(shù)、實(shí)例

eslint

camelcase

// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}

// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
使用大駝峰式命名類(lèi)

eslint

new-cap

// bad
function user(options) {
  this.name = options.name;
}

const bad = new user({
  name: "nope",
});

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

const good = new User({
  name: "yup",
});
不要使用前置或后置下劃線(除非引入的第三方庫(kù)本身使用)

eslint

no-underscore-dangle

JavaScript 沒(méi)有私有屬性或私有方法的概念。盡管前置下劃線通常的概念上意味著“private”,事實(shí)上,這些屬性是完全公有的,因此這部分也是你的API的內(nèi)容。這一概念可能會(huì)導(dǎo)致開(kāi)發(fā)者誤以為更改這個(gè)不會(huì)導(dǎo)致崩潰或者不需要測(cè)試。 如果你想要什么東西變成“private”,那就不要讓它在這里出現(xiàn)。
// bad
this.__firstName__ = "Panda";
this.firstName_ = "Panda";
this._firstName = "Panda";

// good
this.firstName = "Panda";
不要保存引用 this

用箭頭函數(shù)或函數(shù)綁定——Function#bind

// bad
function foo() {
  const self = this;
  return function () {
    console.log(self);
  };
}

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

// good
function foo() {
  return () => {
    console.log(this);
  };
}
保證文件名、export 模塊名以及 import 模塊名一致
// file 1 contents
class CheckBox {
  // ...
}
export default CheckBox;

// file 2 contents
export default function fortyTwo() { return 42; }

// file 3 contents
export default function insideDirectory() {}

// in some other file
// bad
import CheckBox from "./checkBox"; // PascalCase import/export, camelCase filename
import FortyTwo from "./FortyTwo"; // PascalCase import/filename, camelCase export
import InsideDirectory from "./InsideDirectory"; // PascalCase import/filename, camelCase export

// bad
import CheckBox from "./check_box"; // PascalCase import/export, snake_case filename
import forty_two from "./forty_two"; // snake_case import/filename, camelCase export
import inside_directory from "./inside_directory"; // snake_case import, camelCase export
import index from "./inside_directory/index"; // requiring the index file explicitly
import insideDirectory from "./insideDirectory/index"; // requiring the index file explicitly

// good
import CheckBox from "./CheckBox"; // PascalCase export/import/filename
import fortyTwo from "./fortyTwo"; // camelCase export/import/filename
import insideDirectory from "./insideDirectory"; // camelCase export/import/directory name/implicit "index"
// ^ supports both insideDirectory.js and insideDirectory/index.js
export default 一個(gè)函數(shù)時(shí)、函數(shù)名小駝峰式,文件與函數(shù)名一致
function makeStyleGuide() {
  // ...
}

export default makeStyleGuide;
當(dāng) export 一個(gè)結(jié)構(gòu)體、類(lèi)、單例、函數(shù)庫(kù)或者對(duì)象時(shí),使用大駝峰式
const Helpers = {
  guid: () => return uuid(),
};

export default Helpers;
簡(jiǎn)稱(chēng)或縮寫(xiě)應(yīng)該全部大寫(xiě)或者全部小寫(xiě)
名字是給人讀的,不是為了適應(yīng)電腦的算法
// bad
import SmsContainer from "./containers/SmsContainer";

// bad
const HttpRequests = [
  // ...
];

// good
import SMSContainer from "./containers/SMSContainer";

// good
const HTTPRequests = [
  // ...
];

// best
import TextMessageContainer from "./containers/TextMessageContainer";

// best
const Requests = [
  // ...
];
使用全大寫(xiě)字母設(shè)置靜態(tài)變量

導(dǎo)出變量

const 定義的, 保證不能被改變

這個(gè)變量是可信的,他的子屬性都是不能被改變的

一般我們都將項(xiàng)目的全局參數(shù)使用這種 全大寫(xiě)+下劃線分隔的常量 來(lái)定義一些系統(tǒng)配置參數(shù)導(dǎo)出,比如 const LIST_VIEW_PAGE_SIZE = 10 可以表示列表頁(yè)每次加載10條數(shù)據(jù);

如果導(dǎo)出項(xiàng)目是一個(gè)對(duì)象,那么必須保證這個(gè)對(duì)象的所有屬性都是不可變的,同時(shí),它的屬性不再是全大寫(xiě),而是使用小寫(xiě)駝峰式。

// bad
const PRIVATE_VARIABLE = "should not be unnecessarily uppercased within a file";

// bad
export const THING_TO_BE_CHANGED = "should obviously not be uppercased";

// bad
export let REASSIGNABLE_VARIABLE = "do not use let with uppercase variables";

// ---

// allowed but does not supply semantic value
export const apiKey = "SOMEKEY";

// better in most cases
export const API_KEY = "SOMEKEY";

// ---

// bad - unnecessarily uppercases key while adding no semantic value
export const MAPPING = {
  KEY: "value"
};

// good
export const MAPPING = {
  key: "value"
};
訪問(wèn)器 若非必要,不要使用訪問(wèn)器

由于 JavaScript 的 getters/setters 是有副作用的,而且會(huì)讓他人在查看代碼的時(shí)候難以理解,后期也會(huì)難以維護(hù),所以不推薦使用訪問(wèn)器函數(shù),如果非要使用,可以使用自己實(shí)現(xiàn)的 getVal()setVal()。

// bad
class Dragon {
  get age() {
    // ...
  }

  set age(value) {
    // ...
  }
}

// good
class Dragon {
  getAge() {
    // ...
  }

  setAge(value) {
    // ...
  }
}
如果屬性或者方法是一個(gè)布爾判斷值,那么使用 isVal() 或者 hasVal()。
// bad
if (!dragon.age()) {
  return false;
}

// good
if (!dragon.hasAge()) {
  return false;
}
如果非要使用 get()set(),那么它們兩者必須同時(shí)使用
class Jedi {
  constructor(options = {}) {
    const lightsaber = options.lightsaber || "blue";
    this.set("lightsaber", lightsaber);
  }

  set(key, val) {
    this[key] = val;
  }

  get(key) {
    return this[key];
  }
}
事件

當(dāng)你需要向事件附加數(shù)據(jù)時(shí),將數(shù)據(jù)封裝成為一個(gè)對(duì)象,而不是使用原始值,這會(huì)使得以后可以很方便的增加附加值的字段。

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

// ...

$(this).on("listingUpdated", (e, listingID) => {
  // do something with listingID
});

而是:

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

// ...

$(this).on("listingUpdated", (e, data) => {
  // do something with data.listingID
});
jQuery 為所有 jQuery 對(duì)象加上 $ 前綴
// bad
const sidebar = $(".sidebar");

// good
const $sidebar = $(".sidebar");

// good
const $sidebarBtn = $(".sidebar-btn");
緩存 jQuery 結(jié)果
// bad
function setSidebar() {
  $(".sidebar").hide();

  // ...

  $(".sidebar").css({
    "background-color": "pink",
  });
}

// good
function setSidebar() {
  const $sidebar = $(".sidebar");
  $sidebar.hide();

  // ...

  $sidebar.css({
    "background-color": "pink",
  });
}
使用級(jí)聯(lián)查詢 $(".sidebar ul") 或者子父級(jí)查詢 $(".sidebar > ul") 在 jQuery 對(duì)象查詢作用域下使用 find 方法
// bad
$("ul", ".sidebar").hide();

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

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

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

// good
$sidebar.find("ul").hide();
ES5 兼容性

直接參考 Kangax 提供的 ES5 兼容性列表

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/109711.html

相關(guān)文章

  • JavaScript 編碼規(guī)范

    摘要:這樣的變量增加了代碼量,并且混淆讀者。錯(cuò)誤代碼示例變量雖然聲明了,但沒(méi)被使用持續(xù)更新 JavaScript 編碼規(guī)范 一、命名規(guī)范 1. 變量 命名方法:小駝峰式命名法(由小寫(xiě)字母開(kāi)始,后續(xù)每個(gè)單詞首字母都大寫(xiě)) 命名建議:語(yǔ)義化的名詞 特殊:布爾值變量建議添加符合其含義的前綴動(dòng)詞 is:是否 can:能不能 has:有沒(méi)有 示例: // 頁(yè)面標(biāo)題 let pageT...

    wenshi11019 評(píng)論0 收藏0
  • HTML編碼規(guī)范

    摘要:當(dāng)然我們還可以引入框架,這些框架一般都自帶模板處理引擎,比如等語(yǔ)義化命名和語(yǔ)義化標(biāo)簽我們盡量多采用語(yǔ)義化來(lái)命名,并且采用語(yǔ)義化標(biāo)簽來(lái)書(shū)寫(xiě)代碼,多用中新增的標(biāo)簽來(lái)書(shū)寫(xiě)。 1.黃金法則(Golden rule) 不管有多少人參與同一個(gè)項(xiàng)目,一定要確保每一行代碼都像是同一個(gè)人編寫(xiě)的。 Every line of code should appear to be written by a si...

    nifhlheimr 評(píng)論0 收藏0
  • 在 React-CRA 應(yīng)用中配合 VSCode 使用 ESLint 實(shí)踐前端代碼規(guī)范

    摘要:編碼規(guī)范是獨(dú)角獸公司內(nèi)部的編碼規(guī)范,該項(xiàng)目是上很受歡迎的一個(gè)開(kāi)源項(xiàng)目,在前端開(kāi)發(fā)中使用廣泛,本文的配置規(guī)則就是以編碼規(guī)范和編碼規(guī)范作為基礎(chǔ)的。 更新時(shí)間:2019-01-22React.js create-react-app 項(xiàng)目 + VSCode 編輯器 + ESLint 代碼檢查工具 + Airbnb 編碼規(guī)范 前言 為什么要使用 ESLint 在項(xiàng)目開(kāi)發(fā)過(guò)程中,編寫(xiě)符合團(tuán)隊(duì)編碼規(guī)...

    Hujiawei 評(píng)論0 收藏0
  • 編碼規(guī)范 —— 編寫(xiě)靈活、穩(wěn)定、高質(zhì)量的 HTML 和 CSS 代碼的規(guī)范

    摘要:用兩個(gè)空格代替制表符這是唯一能保證在所有環(huán)境下獲得一致展現(xiàn)的方法。編輯器配置將你的編輯器按照下面的配置進(jìn)行設(shè)置,以免常見(jiàn)的代碼不一致和差異用兩個(gè)空格代替制表符保存文件時(shí)刪除尾部的空白符設(shè)置文件編碼為在文件結(jié)尾添加一個(gè)空白行。 黃金定律 永遠(yuǎn)遵循同一套編碼規(guī)范 - 可以是這里列出的,也可以是你自己總結(jié)的。如果發(fā)現(xiàn)規(guī)范中有任何錯(cuò)誤,敬請(qǐng)指正。 HTML 語(yǔ)法 用兩個(gè)空格代替制表符 (ta...

    Karuru 評(píng)論0 收藏0
  • 編碼規(guī)范-html.md

    摘要:寫(xiě)在前面對(duì)于不同的編程語(yǔ)言來(lái)說(shuō),具體的編碼規(guī)范各不相同,但是其宗旨都是一致的,就是保證代碼在高質(zhì)量完成需求的同時(shí)具備良好的可讀性可維護(hù)性。減少標(biāo)簽的數(shù)量編寫(xiě)代碼時(shí),盡量避免多余的父元素。 寫(xiě)在前面 對(duì)于不同的編程語(yǔ)言來(lái)說(shuō),具體的編碼規(guī)范各不相同,但是其宗旨都是一致的,就是保證代碼在高質(zhì)量完成需求的同時(shí)具備良好的可讀性、可維護(hù)性。 本文大部分內(nèi)容來(lái)自網(wǎng)上,僅供個(gè)人參考學(xué)習(xí)! 網(wǎng)絡(luò)上的知...

    tomlingtm 評(píng)論0 收藏0
  • 編寫(xiě)靈活、穩(wěn)定、高質(zhì)量的HTML代碼的規(guī)范

    摘要:六字符編碼通過(guò)明確聲明字符編碼,能夠確保瀏覽器快速并容易的判斷頁(yè)面內(nèi)容的渲染方式。十一減少標(biāo)簽的數(shù)量編寫(xiě)代碼時(shí),盡量避免多余的父元素。未完待續(xù)編寫(xiě)靈活穩(wěn)定高質(zhì)量的代碼的規(guī)范閱讀更多 一、唯一定律 無(wú)論有多少人共同參與同一項(xiàng)目,一定要確保每一行代碼都像是唯一個(gè)人編寫(xiě)的。 二、HTML 2.1 語(yǔ)法 (1)用兩個(gè)空格來(lái)代替制表符(tab) -- 這是唯一能保證在所有環(huán)境下獲得一致展現(xiàn)的方法...

    anquan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<