Airbnb JavaScript Style 阅读注解 下

简介: Airbnb JavaScript Style 阅读注解 下

Whitespace(空格)

  • 使用 tab 去设置两个空格
// bad
function foo() {
∙∙∙∙let name;
}
// bad
function bar() {
∙let name;
}
// good
function baz() {
∙∙let name;
}
  • 使用 {} 之前空一格
// bad
function test(){
  console.log('test');
}
// good
function test() {
  console.log('test');
}
// bad
dog.set('attr',{
  age: '1 year',
  breed: 'Bernese Mountain Dog',
});
// good
dog.set('attr', {
  age: '1 year',
  breed: 'Bernese Mountain Dog',
});
  • 判断语句(if,while)左括号之前加一个空格,在函数声明,函数调用,参数列表的 () 不需要空格
// bad
if(isJedi) {
  fight ();
}
// good
if (isJedi) {
  fight();
}
// bad
function fight () {
  console.log ('Swooosh!');
}
// good
function fight() {
  console.log('Swooosh!');
}
  • 操作符之间要加空格
// bad
const x=y+5;
// good
const x = y + 5;
  • 文件导出通过换行符结束
// bad
import { es6 } from './AirbnbStyleGuide';
  // ...
export default es6;
// bad
import { es6 } from './AirbnbStyleGuide';
  // ...
export default es6;↵
// good
import { es6 } from './AirbnbStyleGuide';
  // ...
export default es6;↵
  • 如果写一个长的方法链(连续使用超过三个方法)时,使用缩进来表示层级关系。使用前导点来表示该行是一个方法调用而不是一个新的语句
// 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;
  • 块内不要空行
// bad
function bar() {
  console.log(foo);
}
// bad
if (baz) {
  console.log(qux);
} else {
  console.log(foo);
}
// bad  
class Foo {
  constructor(bar) {
    this.bar = bar;
  }
}
// good
function bar() {
  console.log(foo);
}
// good
if (baz) {
  console.log(qux);
} else {
  console.log(foo);
}
  • () 里面不要加空格
// bad
function bar( foo ) {
  return foo;
}
// good
function bar(foo) {
  return foo;
}
// bad
if ( foo ) {
  console.log(foo);
}
// good
if (foo) {
  console.log(foo);
}
  • [] 不要随意加空格
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);
// good
const foo = [1, 2, 3];
console.log(foo[0]);
  • {} 里面要加空格
// bad
const foo = {clark: 'kent'};
// good
const foo = { clark: 'kent' };
  • 除了之前提到的长字符串,避免出现一行代码超过100个字符的情况,这样确保了可维护性和可读性
// 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://airbnb.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://airbnb.com/',
  data: { name: 'John' },
})
  .done(() => console.log('Congratulations!'))
  .fail(() => console.log('You have failed this city.'));

Commas(逗号)

  • 逗号不要放在行首
// 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',
};

有时需要附加的逗号,一是为了在 git 上能保持一致,因为 git 在增减之后都会带上逗号,二是一些像Babel这样的转译器会自动删除不必要的逗号,这意味着不必担心传统浏览器中的逗号尾随问题

// bad - git diff without trailing comma
const hero = {
     firstName: 'Florence',
-    lastName: 'Nightingale'
+    lastName: 'Nightingale',
+    inventorOf: ['coxcomb chart', 'modern nursing']
};
// good - git diff with trailing comma
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 (note that a comma must not appear after a "rest" element)
function createHero(
  firstName,
  lastName,
  inventorOf,
  ...heroArgs
) {
  // does nothing
}
// bad
createHero(
  firstName,
  lastName,
  inventorOf
);
// good
createHero(
  firstName,
  lastName,
  inventorOf,
);
// good (note that a comma must not appear after a "rest" element)
createHero(
  firstName,
  lastName,
  inventorOf,
  ...heroArgs
);

Semicolons(分号)

  • 在代码的结尾一定要用 ; 结尾,防止javascript的自动分号插入机制使整个程序报错
// bad - raises exception
const luke = {}
const leia = {}
[luke, leia].forEach(jedi => jedi.father = 'vader')
// bad - raises exception
const reaction = "No! That's impossible!"
(async function meanwhileOnTheFalcon(){
  // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
  // ...
}())
// bad - returns `undefined` instead of the value on the next line - always happens when `return` is on a line by itself because of ASI!
function foo() {
  return
    'search your feelings, you know it to be foo'
}
// good
const luke = {};
const leia = {};
[luke, leia].forEach((jedi) => {
  jedi.father = 'vader';
});
// good
const reaction = "No! That's impossible!";
(async function meanwhileOnTheFalcon(){
  // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
  // ...
}());
// good
function foo() {
  return 'search your feelings, you know it to be foo';
}

Type Casting & Coercion(强制类型转换)

  • 在语句开始进行强制类型转换
  • String 类型
// => 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(); // isn’t guaranteed to return a string
// good
const totalScore = String(this.reviewScore);
  • Number 类型,用 Number 或者 parseInt 进行强制转换,通常 parseInt 需要一个基数来解析字符串
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);

如果 parseInt 是你代码的瓶颈,你不得不使用移位符来进行转换时,一定要在注释里面说明

// good
/**
 * parseInt was the reason my code was slow.
 * Bitshifting the String to coerce it to a
 * Number made it a lot faster.
 */
const val = inputValue >> 0;
  • 使用移位操作符时需要注意,数字可以表示为64位,但是移位操作符始终返回32位的源,对于大于32位的整数,移位操作可能会导致意外发生。最大的32位支持是 2,147,483,647
2147483647 >> 0; // => 2147483647
2147483648 >> 0; // => -2147483648
2147483649 >> 0; // => -2147483647
  • Booleans 类型
const age = 0;
// bad
const hasAge = new Boolean(age);
// good
const hasAge = Boolean(age);
// best
const hasAge = !!age;

Naming Conventions(命名协议)

  • 避免使用单字符命名,注意命名描述
// bad
function q() {
  // ...
}
// good
function query() {
  // ...
}
  • 命名对象,函数和实例时都使用驼峰命名
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}
// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
  • 对命名对象和构造函数时使用帕斯卡命名
// 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',
});
  • 头部,尾部不要使用下划线,因为JavaScript的属性或者方法没有隐私的概念。前导下换线是一个常见的惯例,表示“私人”,事实上,这些属性是完全公开的,这样会让人产生误解
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
this._firstName = 'Panda';
// good
this.firstName = 'Panda';
  • 不要保存 this 指针,使用箭头函数或者 # 绑定来取代
// 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);
  };
}
  • 基本文件名应该与其导出名字对应
// 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
  • 默认导出一个方法时,使用驼峰命名表示。同时,你的文件名应该与方法名一致
function makeStyleGuide() {
  // ...
}
export default makeStyleGuide;
  • 导出构造函数,类,单例,函数库等时,使用帕斯卡命名
const AirbnbStyleGuide = {
  es6: {
  },
};
export default AirbnbStyleGuide;
  • 缩略词应该全是大小字母或者全是小写字母构成,这样才有可读性
// bad
import SmsContainer from './containers/SmsContainer';
// bad
const HttpRequests = [
  // ...
];
// good
import SMSContainer from './containers/SMSContainer';
// good
const HTTPRequests = [
  // ...
];
// also good
const httpRequests = [
  // ...
];
// best
import TextMessageContainer from './containers/TextMessageContainer';
// best
const requests = [
  // ...
];

Accessors(访问方法)

  • 属性的访问方法不是必须的
  • 不要使用JavaScript的 getters/setters,因为它们会造成意想不到的坏的影响,并且很难去测试,定位。所以如果你要用访问函数,使用 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];
  }
}

Events(事件)

  • 当将数据传递到事件方法里面的时候,不要使用原始值直接进行传递,应该处理成对象字面量。这样可以方便其他用户修改或者查看传递数据
// 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选择器缓存起来
// bad
function setSidebar() {
  $('.sidebar').hide();
  // ...
  $('.sidebar').css({
    'background-color': 'pink',
  });
}
// good
function setSidebar() {
  const $sidebar = $('.sidebar');
  $sidebar.hide();
  // ...
  $sidebar.css({
    'background-color': 'pink',
  });
}
  • 对于 DOM 节点的查询使用级联 $('.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();

Standard Library(标准程序库)

  • 使用 Number.isNaN 来代替全局的 isNaN,因为全局的 isNaN 会强制将非数字类型转换为数字类型,任何强制转换为非数字的都会返回true
// bad
isNaN('1.2'); // false
isNaN('1.2.3'); // true
// good
Number.isNaN('1.2.3'); // false
Number.isNaN(Number('1.2.3')); // true
  • 使用 Number.isFinite 来代替全局的 isFinite,因为全局的 isFinite 会强制将非数字类型转换为数字类型,任何强制转换为有限数字的结果都会返回true
// bad
isFinite('2e3'); // true
// good
Number.isFinite('2e3'); // false
Number.isFinite(parseInt('2e3', 10)); // true

Testing(测试)

  • 无论您使用那种框架,都应该测试!
  • 尽量去写一些写的纯函数,并且尽量减少突变情况的发生
  • 谨慎使用 stubs(存根) 和 mocks(虚拟数据),他们会让你的测试更加脆弱
  • Airbnb 主要使用 mocha 来进行测试,偶尔也用 tape 来测试小的独立模块
  • 100%的测试覆盖率是最理想的
  • 每当你修复了一个bug,都需要写一个回归测试。未经回归测试修正的错误,未来一定会重现
目录
相关文章
|
2天前
|
JavaScript 前端开发
|
6月前
|
JavaScript
js改变style中的值
js改变style中的值
|
10月前
|
设计模式 人工智能 前端开发
《现代Javascript高级教程》电子书抢先阅读,了解如何在JavaScript中构建高质量的应用程序!
本书旨在帮助学习者进阶JavaScript编程,涵盖现代JavaScript的高级概念和技术,包括异步编程、函数式编程、模块化开发、ES6+语法等。通过实际项目示例和练习,学习者将深入了解如何在JavaScript中构建高质量的应用程序。
《现代Javascript高级教程》电子书抢先阅读,了解如何在JavaScript中构建高质量的应用程序!
|
自然语言处理 JavaScript 前端开发
Airbnb JavaScript Style 阅读注解 中
Airbnb JavaScript Style 阅读注解 中
144 0
|
JavaScript 前端开发 安全
Airbnb JavaScript Style 阅读注解 上
Airbnb JavaScript Style 阅读注解 上
92 0
|
存储 JavaScript 安全
《JavaScript 面向对象精要》 阅读摘要(下)
高程面向对象这块内容介绍的比较浅显,个人觉得这本小书是高程的补充,看完之后觉得收获匪浅,所以做了个笔记,以备后询 Js中两种基本数据类型:原始类型(基本数据类型)和引用类型; 原始类型保存为简单数据值,引用类型则保存为对象,其本质是指向内存位置的应用。 其它编程语言用栈存储原始类型,用堆存储引用类型,而js则不同:它使用一个变量对象追踪变量的生存期。原始值被直接保存在变量对象里,而引用值则作为一个指针保存在变量对象内,该指针指向实际对象在内存中的存储位置。
《JavaScript 面向对象精要》 阅读摘要(下)
|
存储 Web App开发 JavaScript
《JavaScript 面向对象精要》 阅读摘要(上)
高程面向对象这块内容介绍的比较浅显,个人觉得这本小书是高程的补充,看完之后觉得收获匪浅,所以做了个笔记,以备后询 原始类型和引用类型Js中两种基本数据类型:原始类型(基本数据类型)和引用类型; 原始类型保存为简单数据值,引用类型则保存为对象,其本质是指向内存位置的应用。 其它编程语言用栈存储原始类型,用堆存储引用类型,而js则不同:它使用一个变量对象追踪变量的生存期。原始值被直接保存在变量对象里,而引用值则作为一个指针保存在变量对象内,该指针指向实际对象在内存中的存储位置。
《JavaScript 面向对象精要》 阅读摘要(上)
|
自然语言处理 JavaScript 前端开发
《你不知道的JavaScript》 (上) 阅读摘要
本书属于基础类书籍,会有比较多的基础知识,所以这里仅记录平常不怎么容易注意到的知识点,不会全记,供大家和自己翻阅; 上中下三本的读书笔记: 《你不知道的JavaScript》 (上) 读书笔记 《你不知道的JavaScript》 (中) 读书笔记 《你不知道的JavaScript》 (下) 读书笔记 如果希望获取本书的 PDF 资源,可以关注文末二维码加微信群找群主要~
|
Web App开发 XML 移动开发
JavaScript特性(attribute)、属性(property)和样式(style)
最近在研读一本巨著《JavaScript忍者秘籍》,里面有一篇文章提到了这3个概念。 书中的源码可以在此下载。我将源码放到了线上,如果不想下载,可以直接访问在线网址,修改页面名就能访问到相应示例代码。
JavaScript特性(attribute)、属性(property)和样式(style)
|
JavaScript 前端开发
「注解」《你不知道的JavaScript(上卷)》第三章:函数作用域和块作用域
「注解」《你不知道的JavaScript(上卷)》第三章:函数作用域和块作用域
94 0
「注解」《你不知道的JavaScript(上卷)》第三章:函数作用域和块作用域