为什么? 这样能够确保你不能重新赋值你的引用,否则可能导致错误或者产生难以理解的代码
// bad
var a = 1;
// good
const a = 1;
为什么? let 是块级作用域,而不像 var 是函数作用域.
// bad
var count = 1;
if (true) {
count += 1;
}
// good, use the let.
let count = 1;
if (true) {
count += 1;
}
为什么?更简洁且效率更高
// bad
const item = new Object();
// good
const item = {};
为什么? 这样更容易的判断哪些属性使用的简写。
const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
episodeOne: 1,
twoJediWalkIntoACantina: 2,
lukeSkywalker,
episodeThree: 3,
anakinSkywalker,
};
// good
const obj = {
lukeSkywalker,
anakinSkywalker,
episodeOne: 1,
twoJediWalkIntoACantina: 2,
episodeThree: 3,
};
为什么? 总的来说,我们认为这样更容易阅读。 它提升了语法高亮显示,并且更容易通过许多 JS 引擎优化。
// bad
const bad = {
'foo': 3,
'data-blah': 5,
};
// good
const good = {
foo: 3,
'data-blah': 5,
};
为什么?
1)
const obj = Object.create(null)
const text1 = obj.hasOwnProperty(‘a’)
const text2 = Object.prototype.hasOwnProperty.call(obj, ‘a’)
console.log(text1) // 报错
console.log(text2) // false
2)
可能导致意外行为或服务安全漏洞。例如,web 客户端解析来自远程服务器的 JSON 输入并直接在结果对象上调用 hasOwnProperty 是不安全的,因为恶意服务器可能发送一个JSON值,如 {“hasOwnProperty”: 1},扰乱业务和安全。
// bad
console.log(object.hasOwnProperty(key));
// good
console.log(Object.prototype.hasOwnProperty.call(object, key));
// best
const has = Object.prototype.hasOwnProperty; // 在模块范围内的缓存中查找一次
// ...
console.log(has.call(object, key));
为什么?更简洁且效率更高
// bad
const items = new Array();
// good
const items = [];
// bad
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i < len; i += 1) {
itemsCopy[i] = items[i];
}
// good
const itemsCopy = [...items];
// bad
const name = "Capt. Janeway";
// bad - 模板文字应该包含插值或换行。
const name = `Capt. Janeway`;
// good
const name = 'Capt. Janeway';
为什么? 字符串模板为您提供了一种可读的、简洁的语法,具有正确的换行和字符串插值特性。
// bad
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// bad
function sayHi(name) {
return ['How are you, ', name, '?'].join();
}
// bad
function sayHi(name) {
return `How are you, ${ name }?`;
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
为什么?因为arguments为每个函数的隐式参数
// bad
function foo(name, options, arguments) {
// ...
}
// good
function foo(name, options, args) {
// ...
}
5.不要使用 arguments, 选择使用 rest 语法 … 代替
为什么?… 明确了你想要拉取什么参数。 更甚, rest 参数是一个真正的数组,而不仅仅是类数组的 arguments 。
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
// really bad
function handleThings(opts) {
// No! We shouldn’t mutate function arguments.
// Double bad: if opts is falsy it'll be set to an object which may
// be what you want but it can introduce subtle bugs.
opts = opts || {};
// ...
}
// still bad
function handleThings(opts) {
if (opts === void 0) {
opts = {};
}
// ...
}
// good
function handleThings(opts = {}) {
// ...
}
// bad
function handleThings(opts = {}, name) {
// ...
}
// good
function handleThings(name, opts = {}) {
// ...
}
为什么? 以这种方式创建一个函数将对一个类似于 eval() 的字符串进行计算,这将打开漏洞。
// bad
var add = new Function('a', 'b', 'return a + b');
// still bad
var subtract = Function('a', 'b', 'return a - b');
为什么? 重新赋值参数会导致意外的行为,尤其是在访问 arguments 对象的时候。 它还可能导致性能优化问题,尤其是在 V8 中。
// bad
function f1(a) {
a = 1;
// ...
}
function f2(a) {
if (!a) { a = 1; }
// ...
}
// good
function f3(a) {
const b = a || 1;
// ...
}
function f4(a = 1) {
// ...
}
const luke = {
jedi: true,
age: 28,
};
// bad
const isJedi = luke['jedi'];
// good
const isJedi = luke.jedi;
为什么?
1) 这样更容易添加新的变量声明,而且你不必担心是使用 ; 还是使用 , 或引入标点符号的差别。 你可以通过 debugger 逐步查看每个声明,而不是立即跳过所有声明。
2)这在后边如果需要根据前边的赋值变量指定一个变量时很有用。
// 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 example() {
// JavaScript 把它解释为
// let a = ( b = ( c = 1 ) );
// let 关键词只适用于变量 a ;变量 b 和变量 c 则变成了全局变量。
let a = b = c = 1;
}());
console.log(a); // throws ReferenceError
console.log(b); // 1
console.log(c); // 1
// good
(function example() {
let a = 1;
let b = a;
let c = a;
}());
console.log(a); // throws ReferenceError
console.log(b); // throws ReferenceError
console.log(c); // throws ReferenceError
// 对于 `const` 也一样
// bad
if (isValid === true) {
// ...
}
// good
if (isValid) {
// ...
}
// bad
if (name) {
// ...
}
// good
if (name !== '') {
// ...
}
// bad
if (collection.length) {
// ...
}
// good
if (collection.length > 0) {
// ...
}
为什么? 语法声明在整个 switch 块中都是可见的,但是只有在赋值的时候才会被初始化,这种情况只有在 case 条件达到才会发生。 当多个 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 {}
}
}
// bad
const foo = maybe1 > maybe2
? "bar"
: value1 > value2 ? "baz" : null;
// 分离为两个三目表达式
const maybeNull = value1 > value2 ? 'baz' : null;
// better
const foo = maybe1 > maybe2
? 'bar'
: maybeNull;
// best
const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
为什么? 这能提高可读性并且表明开发人员的意图。
在编写代码注释时,使用 /** … */ 来进行多行注释,而不是 // 。
使用 // 进行单行注释。 将单行注释放在需要注释的行的上方新行。 在注释之前放一个空行,除非它在块的第一行。用一个空格开始所有的注释,使它更容易阅读。
// bad
const active = true; //is current tab
// good
// is current tab
const active = true;
// bad
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
// good
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
// also good
function getType() {
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
为什么?其他方法都有它的问题,或者会出现执行出错的可能;
let reviewScore = 9;
// bad
const totalScore = new String(reviewScore); // typeof totalScore is "object" not "string"
// bad
const totalScore = reviewScore + ''; // Symbol('123') + ‘’报错
// bad
const totalScore = reviewScore.toString(); // 值为null 或者undefined就会报错
// good
const totalScore = String(reviewScore);
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);
const age = 0;
// bad
const hasAge = new Boolean(age);
// good
const hasAge = Boolean(age);
// best
const hasAge = !!age;
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}
// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
为什么? 名字是为了可读性,不是为了满足计算机算法。
// bad
import SmsContainer from './containers/SmsContainer';
// bad
const HttpRequests = [
// ...
];
// good
import SMSContainer from './containers/SMSContainer';
// good
const HTTPRequests = [
// ...
];
// also good
const httpRequests = [
// ...
];
组件应该命名为多个单词的,且格式为单词大写开头(PascalCase)如’TodoItem’。
基础组件(也就是展示类的、无逻辑的或无状态的组件)命名应该全部以一个特定的前缀开头,比如 Base、App 或 V。
components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue
components/
|- TheHeading.vue
|- TheSidebar.vue
components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue
PascalBase
风格;camelCase
风格;Api
的,统一加上Api
后缀;除index.vue之外,其他.vue文件统一用PascalBase
风格;
统一使用kebab-case
命名风格;
为什么呢?HTML 并不支持自闭合的自定义元素;
而没有内容的单文件组件/字符串模板加上末尾闭合标签显得更已读,也使代码变得简洁;
<MyComponent/>
<my-component/>
为什么呢?HTML是大小写不敏感的,在DOM模板中必须仍使用kebab-case。
<!-- 在 DOM 模板中 -->
<my-component></my-component>
<!-- 在 单文件.vue 模板/字符串模板中,我们推荐首字母大写,更醒目和方便(自动补全名字) -->
<MyComponent></MyComponent>
反例
// 这样做只有开发原型系统时可以接受
props: ['status']
为什么? 组件和布局组件中的样式可以是全局的
<template>
<button class="button button-close">X</button>
</template>
<!-- 使用 `scoped` attribute -->
<style scoped>
.button-close {
background-color: red;
}
</style>
为什么?会使得数据逻辑脉络更清楚,更易追踪。
<button @click="onSendOut(params, info.orderId)">发 货button>
如:
onSubmitForm() / getListData() / handleListData()
为什么? 解构可以避免为这些属性创建临时引用。
// 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}`;
}
const arr = [1, 2, 3, 4];
// bad
const first = arr[0];
const second = arr[1];
// good
const [first, second] = arr;
为什么? 你可以随时添加新的属性或者改变属性的顺序,而不用修改调用方。
// bad
function processInput(input) {
// 处理代码...
return [left, right, top, bottom];
}
// 调用者需要考虑返回数据的顺序。
const [left, __, top] = processInput(input);
// good
function processInput(input) {
// 处理代码...
return { left, right, top, bottom };
}
// 调用者只选择他们需要的数据。
const { left, top } = processInput(input);
使用 map() / every() / filter() / find() / findIndex() / reduce() / some() / … 遍历数组, 和使用 Object.keys() / Object.values() / Object.entries() 迭代你的对象生成数组。
为什么? 因为它们返回纯函数。
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);
为什么? 要求操作符在行的开始保持对齐并遵循类似方法衔接的模式。 这提高了可读性,并且使更复杂的逻辑更容易直观的被理解。
// 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();
}
当出现多种条件判断从而需要多重嵌套代码的时候,可以用
if + return
的方式,这样更加简洁和易读
// bad
function func(a, b, c, d){
if(a !== null){
if (b !== 2){
if (c !== "OK"){
// code
}
}
}
}
// good
function func(a, b, c, d){
if(a === null) return
if (b === 2) return
if (c === "OK") return
// code
}
// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // 变异的 `original` ಠ_ಠ
delete copy.a; // 这....
// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }