国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JavaScript 編碼規(guī)范

newsning / 2479人閱讀

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

類型 基本類型

你可以直接獲取到基本類型的值

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 類型。
復(fù)雜類型

復(fù)雜類型賦值就是獲取到他的引用的值,相當(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

為了確保你不會改變你的初始值,重復(fù)引用會導(dǎo)致一些不可預(yù)見的 bug,還會讓代碼難以理解,所有的賦值都應(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

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

eslint

no-var

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

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

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

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

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

eslint

no-new-object

// bad
const obj = new Object();

// good
const obj = {};
使用計算屬性名

當(dāng)你需要創(chuàng)建一個帶有 動態(tài)屬性名 的對象時,請將所有的屬性定義放在一起,可以使用 計算屬性名

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
};
對象方法簡寫

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;
  }
};
屬性值縮寫

eslint

object-shorthand

const name = "Parc MG";

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

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

// bad
const org = {
  email: "contact@parcmg.com",
  name,
  created: new Date(),
  url,
};

// good
const org = {
  name,
  url,
  email: "contact@parcmg.com",
  created: new Date(),
};
若非必要,屬性名不使用 ""

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)用對象原型上的方法

不直接調(diào)用一個對象的 hasOwnPropertypropertyIsEnumerableisPrototypeOf 等這些原型的方法,在某些情況下,這些方法可能會被屏蔽掉,比如 { hasOwnProperty: false } 或者是一個空對象 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)算 ...

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

在獲取對象指定的幾個屬性時,使用解構(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; // 這樣操作之后會導(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; // 從對象 obj 中解構(gòu)出 a, b 兩個屬性的值,并賦值給名為 a,b 的常量
const { a, ...rest } = obj; // 從對象 obj 中解構(gòu)出 a 的值,并賦值給名為 a 的常量,同時,創(chuàng)建一個由所有其它屬性組成的名為 `rest` 的新對象
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}`;
返回多值時,使用對象解構(gòu),而非數(shù)組結(jié)構(gòu)

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

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

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

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

const { left, top } = processInput(input); // 調(diào)用者可以明確的指定需要哪個值,而且不需要創(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)需要將一個可迭代的對象轉(zhuǎn)換成數(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 將類數(shù)組對象轉(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 對類數(shù)組對象進(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));
一個數(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,
];
字符串 string 永遠(yuǎn)使用單引號 ""

eslint

quotes

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

const name = `Parc M.G`;

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

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

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

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

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

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

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

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 的定義是:一系列語句,但函數(shù)聲明不是一個語句,命名函數(shù)表達(dá)式是一個語句。

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

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

arguments 的優(yōu)先級高于高于每個函數(shù)作用域自帶的 arguments 對象,這會導(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

... 明確出你想用那個參數(shù),同時,rest 是一個真數(shù)組,而不是一個類數(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)對參數(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ù)體內(nèi)不允許被重新賦值(包含參數(shù)本身,若參數(shù)為對象,還包括該對象所有屬性的值),
一個函數(shù)應(yīng)該是沒有任何副作用的。
// 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ù)簽名包含多個參數(shù)需要使用多行,那就每行有且僅有一個參數(shù)
// bad
function foo(bar,
             baz,
             quux) {
  // ...
}

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

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

// good
console.log(
  foo,
  bar,
  baz,
);
箭頭函數(shù) 當(dāng)你一定要用函數(shù)表達(dá)式的時候,就使用箭頭函數(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ù)體有且僅有一個沒有副作用的表達(dá)式,那么刪除大括號和 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
// 這種情況會return bool = true, 不好
foo(() => bool = true);

// good
foo(() => {
  bool = true;
});
若表達(dá)式包含多行,用圓括號包裹起來
// 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ù)只有一個參數(shù),且沒有大括號,那就刪除圓括號,否則,參數(shù)總是放在圓括號里。

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ù)體的位置, 就寫在箭頭后面

eslint

implicit-arrow-linebreak

// bad
(foo) =>
  bar;

(foo) =>
  (bar);

// good
(foo) => bar;
(foo) => (bar);
(foo) => (
   bar
)
類與構(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 實現(xiàn)繼承

它是一種內(nè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 實現(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);
只要保證可以正常工作且沒有副作用,可以自已定制 toString 方法
class Jedi {
  constructor(options = {}) {
    this.name = options.name || "no name";
  }

  getName() {
    return this.name;
  }

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

eslint

no-useless-constructor

// bad
class Jedi {
  constructor() {}

  getName() {
    return this.name;
  }
}

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

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

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
雖然一行是簡潔的,有一個明確的方式進(jìn)口和一個明確的出口方式來保證一致性。
// bad
export { es6 as default } from "./Component";

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

eslint

no-duplicate-imports

從同一個路徑下import多行會使代碼難以維護(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)你要輸出可變的綁定。雖然在某些場景下可能需要這種技術(shù),但總的來說應(yīng)該導(dǎo)出常量。
// bad
let foo = 3;
export { foo }

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

eslint

import/prefer-default-export

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

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

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ù)組和對象字面量
花括號與樣式指南中每個其他花括號塊遵循相同的縮進(jìn)規(guī)則,逗號也是。
// bad
import {longNameA, longNameB, longNameC, longNameD, longNameE} from "path";

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

eslint

import/no-webpack-loader-syntax

一旦用 Webpack 語法在 import 里會把代碼耦合到模塊綁定器。最好是在 webpack.config.js 里寫 webpack loader 語法
// 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高級函數(shù)代替 for-infor-of

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

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

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

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上支持的不好

如果一定要用,那么一定需要注意一點:function* 是同一概念關(guān)鍵字, * 并不是 function 的修飾符, function* 是一個與 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* () {
  // ...
}
屬性 訪問屬性使用 .

eslint

dot-notation

這條,涉及一個曾經(jīng)阿里出過一個看似簡單,實則很難的面試題,你就算猜對一個,你也不一定能說出原理:

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

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

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

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

// good
const isJedi = luke.jedi;
當(dāng)獲取屬性名稱本身是一個變量是,使用 [] 訪問
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();
每一個變量都用一個 const 或者 let

eslint

one-var

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

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

// 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";
塵歸塵,土歸土

在同一個塊中,所有的 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;
  }

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

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

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

eslint

no-multi-assign

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

// bad
(function example() {
  // JavaScript 將這一段解釋為
  // let a = ( b = ( c = 1 ) );
  // let 只對變量 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 文檔,一元增量和減量語句受到自動分號插入的影響,并且可能會導(dǎo)致應(yīng)用程序中的值遞增或遞減的無聲錯誤。 使用 num + = 1 而不是 num ++num ++ 語句來表達(dá)你的值也是更有表現(xiàn)力的。 禁止一元增量和減量語句還會阻止您無意地預(yù)增/預(yù)減值,這也會導(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;
賦值時不換行

eslint

operator-linebreak

如果賦值語句超出了 max-len 配置,那么給值前面加上括號。

// 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;

// 寫了沒用
var y = 10;
y = 5;

// 變量改了自己的值,也沒有用這個變量
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" 即使沒有使用也可以可以被忽略, 因為這個有一個 rest 取值的屬性。
// 這是從對象中抽取一個忽略特殊字段的對象的一種形式
var { type, ...coords } = data;
// "coords" 現(xiàn)在就是一個沒有 "type" 屬性的 "data" 對象
變量提升 永遠(yuǎn)不要使用 var

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

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

// 在你引用的地方之后聲明一個變量,他會正常輸出是因為變量作用域上升。
// 注意: declaredButNotAssigned的值沒有上升
function example() {
  console.log(declaredButNotAssigned); // => undefined
  var declaredButNotAssigned = true;
}

// 解釋器把變量聲明提升到作用域最前面,
// 可以重寫成如下例子, 二者意義相同
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 條件語句的強(qiáng)制 toBoolean

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

Objects 總是計算成 true

Undefined 總是計算 成 false

Null 總是計算成 false

Booleans 計算成它本身的布爾值

Numbers

+0-0 或者 NaN 總是計算成 false

其它的全部為 true

Strings

"" 計算成 false

其它全部為 true

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

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

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

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

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

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

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

eslint

no-case-declarations

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

// 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)先級顯而易見,否則使用圓括號來混合操作符

eslint

no-mixed-operators

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

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

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

// bad
// 別人會陷入(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ū)塊 用大括號包裹多行代碼

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)閉大括號在同一行

eslint

brace-style

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

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

eslint

no-else-return

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

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

// 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;
  }
}
控制語句 當(dāng)你的控制語句 (ifwhile)等太長,或者超過最大長度限制時,把每一個判斷條件都放到多帶帶一行去,邏輯操作符放在行首
// 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();
}
不要用選擇操作符代替控制語句
// bad
!isRunning && startRunning();

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

  // ...

  return element;
}

// good
/**
 * make() 基于傳入的 `tag` 名返回一個新元素
 * @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;
}
所有注釋開頭空一個,方便閱讀

eslint

space-comment

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

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

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

  // ...

  return element;
}

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

  // ...

  return element;
}
積極使用 FIXMETODO

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

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

TODO:計劃在這里去實現(xiàn)某些功能,現(xiàn)在還沒有實現(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)該從一個參數(shù)中獲取并初始化
    this.total = 0;
  }
}
空格 代碼縮進(jìn)總是使用兩個空格

eslint

indent

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

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

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

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

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

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

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

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

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

eslint

space-infix-ops

// bad
const x=y+5;

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

eslint

eol-last

// bad
function doSmth() {
  var foo = 2;
}
// good
function doSmth() {
  var foo = 2;
}
使用多行縮進(jìn)的方式進(jìn)行一個長方法鏈調(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);
在一個代碼塊后下一條語句前空一行
// 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);
}
圓括號里不加空格

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);
}
方括號里,首尾都不要加空格與元素分隔

eslint

array-bracket-spacing

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

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

eslint

object-curly-spacing

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

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

eslint

max-len

為了確保代碼的人類可讀性與可維護(hù)性,代碼行應(yī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ī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];
計算屬性內(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ù)名和小括號之間不要空格

eslint

func-call-spacing

// bad
func ();

func
();

// good
func();
在對象的字面量屬性中, 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ù)多個空行,文件末尾只允許空一行

eslint

no-multiple-empty-lines

// bad
var x = 1;



var y = 2;

// good
var x = 1;

var y = 2;
逗號 不要前置逗號

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é)尾逗號

eslint

comma-dangle

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

// good - 有結(jié)尾逗號的 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 (在一個 "rest" 元素后面,絕對不能出現(xiàn)逗號)
function createHero(
  firstName,
  lastName,
  inventorOf,
  ...heroArgs
) {
  // does nothing
}

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

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

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

eslint

semi

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

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

// good, 行首加分號,避免文件被連接到一起時立即執(zhí)行函數(shù)被當(dāng)做變量來執(zhí)行。
;(() => {
  const name = "Skywalker";
  return name;
}());
強(qiáng)類型轉(zhuǎn)換 在語句開始執(zhí)行強(qiáng)制類型轉(zhuǎn)換 使用 String 進(jìn)行字符類型轉(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ù)字類型轉(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);
在注釋中說明為什么要使用移位運(yùn)算

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

// good
/**
 * parseInt是代碼運(yùn)行慢的原因
 * 用Bitshifting將字符串轉(zhuǎn)成數(shù)字使代碼運(yùn)行效率大幅增長
 */
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ī)則 避免使用一個字母命名

eslint

id-length

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

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

eslint

camelcase

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

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

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",
});
不要使用前置或后置下劃線(除非引入的第三方庫本身使用)

eslint

no-underscore-dangle

JavaScript 沒有私有屬性或私有方法的概念。盡管前置下劃線通常的概念上意味著“private”,事實上,這些屬性是完全公有的,因此這部分也是你的API的內(nèi)容。這一概念可能會導(dǎo)致開發(fā)者誤以為更改這個不會導(dǎo)致崩潰或者不需要測試。 如果你想要什么東西變成“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 一個函數(shù)時、函數(shù)名小駝峰式,文件與函數(shù)名一致
function makeStyleGuide() {
  // ...
}

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

export default Helpers;
簡稱或縮寫應(yīng)該全部大寫或者全部小寫
名字是給人讀的,不是為了適應(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 = [
  // ...
];
使用全大寫字母設(shè)置靜態(tài)變量

導(dǎo)出變量

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

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

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

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

// 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"
};
訪問器 若非必要,不要使用訪問器

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

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

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

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

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

// good
if (!dragon.hasAge()) {
  return false;
}
如果非要使用 get()set(),那么它們兩者必須同時使用
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ù)據(jù)封裝成為一個對象,而不是使用原始值,這會使得以后可以很方便的增加附加值的字段。

// 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 對象加上 $ 前綴
// 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",
  });
}
使用級聯(lián)查詢 $(".sidebar ul") 或者子父級查詢 $(".sidebar > ul") 在 jQuery 對象查詢作用域下使用 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)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/109711.html

相關(guān)文章

  • JavaScript 編碼規(guī)范

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

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

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

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

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

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

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

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

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

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

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

    anquan 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<