AirbnbJavaScript 风格指南
⽬录
1. 类型
1.1 基本类型: 你可以直接获取到基本类型的值。(直接存取)
string ,number ,boolean ,null ,undefined ,symbol ,bigint 。
symbol 为ES6新引⼊的原始数据类型,表⽰独⼀⽆⼆的值,引⼊原因是为了从根本上防⽌对象属性名的冲突,故其作⽤为作为对象属性的标识符。
BigInt  是通过在整数末尾附加 n 或调⽤构造函数来创建的。BigInt  可以表⽰任意⼤的整数。
由于 Symbols 和 BigInts 不能被正确的 polyfill。所以不应在不能原⽣⽀持这些类型的环境或浏览器中使⽤他们。理解这句话:
polyfill 是⽤JavaScript来实现⼀些浏览器不⽀持的原⽣API。
例如,querySelectorAll是很多现代浏览器都⽀持的原⽣Web API,但是有些古⽼的浏览器并不⽀持,
那么假设有⼈写了库,只要⽤了这个库, 你就可以在古⽼的浏览器⾥⾯使⽤document.querySelectorAll,使⽤⽅法跟现代浏览器原⽣API⽆异。那么这个库就可以称为Polyfill或者Polyfiller。⼀个Polyfill 是⽤来抹平新⽼浏览器标准原⽣API  之间的差距。⽬前bigInt 浏览器⽀持情况并不理想,只有 Chrome ⽀持较好,其他浏览器⽀持不好。由于和其他 JavaScript  新特性不同,BigInt 不能很好的被编译为 ES5。因为 BigInt  中修改了运算符的⼯作⾏为,这些⾏为是不能直接被 polyfill  转换的。如果要使⽤bigInt ⽬前,更好的选择是使⽤JSBI 库,纯JS实现了bigInt 。使⽤JSBI的⼀个优点是,⼀旦浏览器⽀持,就不需要重写代码。相反,可以使⽤babel插件⾃动将JSBI代码编译为原⽣ BigInt代码。
1.2 复杂类型: 复杂类型赋值是获取到他的引⽤的值。
object ,array ,function const  foo = 1;let  bar = foo ;bar = 9;console .log (foo , bar ); // => 1, 9
1
2
3
4
5
6Babel 是⼀个 JavaScript 编译器。他把最新版的javascript 编译成当下可以执⾏的版本,即 利⽤babel 就可以让我们在当前的项⽬中随意的使⽤这些新最新的es6,babel 作⽤: (1)语法转换(将⾼级语法解析为当前可⽤的实现) (2)源代码转换(codemods)    (3)Polyfill ⽬标环境中缺少的功能(通过如 core-js 的第三⽅ polyfill )    babel-core :Babel 编译器的核⼼,Babel 默认只转换新的javascript 句法,⽽不转换新的API ,⽐如Iterator 、Generator 、Set 、Maps 、Proxy 、Reflect 、Symbol
1
2
3
4
5
6
7
8const  foo = [1, 2];const  bar = foo ;bar [0] = 9;console .log (foo [0], bar [0]); // => 9, 9
1
2
3
4
5
6
2. 引⽤
2.1 所有的赋值都⽤ const ,避免使⽤ var 。eslint: prefer-const, no-const-assign
2.2 如果你⼀定要对参数重新赋值,使⽤ let ,⽽不是 var 。eslint: no-var 声明创建⼀个值时⽤ const  ⽽不⽤ var ,这样可以保证你声明的值不会被重定义
在多⼈开发⼀个项⽬时,⽐如都定义了⼀个变量a,但各⾃⽤途不同,后⾯定义的a会把前⾯定义的覆盖掉。
2.3 let 和 const 都是块级作⽤域
2.4 思考:为什么要⽤let 代替var
JS中存在变量提升(变量提升:JavaScript引擎的⼯作⽅式是,先解析代码,获取所有被声明的变量,然后再⼀⾏⼀⾏地运⾏。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting)。带var 和function 挂关键字会导致变量提升)
变量提升会带来⼀些问题:
在创建执⾏上下⽂阶段,变量 i 就已经被提升了,所以当 for 循环结束之后,变量 i 并没有被销毁。ES6 引⼊的 let  和 const  关键字就是为了解决变量提升带来的问题。// const 和 let 都只存在于它被定义的那个块级作⽤域。{  let  a = 1;  const  b = 1;}console .log (a );  // 报错a 未定义console .log (b );  // 报错
1
2
3
4
5
6
7  1. 变量可能会被覆盖掉
1var  myname = 1;function  showName () {  //var myname (变量提升操作)  console .log (myname );    //undefined  if (0) {  var  myname = 2;  }  console .log (myname );    //undefined }showName ();
1
2
3
4
5
6
7
89
10  2. 本应销毁的变量没有被销毁
1function  foo (){  // var i(变量提升)  for  (var  i = 0; i < 7; i ++) {  }  console .log (i );  //7}foo ()
1
2
3
4
5
6
7
8
有两个地⽅都定义了变量 x,第⼀个地⽅在函数块的顶部,第⼆个地⽅在 if 块的内部,由于 var 的作⽤范围是整个函数,所以在编译阶段,最终只⽣成了⼀个变量 x,函数体内所有对 x 的赋值操作都会直接改变变量环境中的 x 值。
let⽀持块级作⽤域,代码块内部定义的变量在代码块外部是访问不到的,并且等该代码块中的代码执⾏完成之后,代码块中定义的变量会被销毁。
3. 对象
3.1 使⽤字⾯值创建对象不⽤new 关键字,⽤{}。
3.2 使⽤计算属性名创建⼀个带有动态属性名的对象
创建拥有动态属性名的对象时,⽤计算属性名来表⽰,这样可以在创建对象时,将所有的属性写在同⼀个地⽅。
3.3 ⽤对象⽅法简写function  varTest () {  var  x = 1;  if  (true ) {    var  x = 2;  // 同样的变量!    console .log (x );  // 2  }  console .log (x );  // 2}
1
2
3
4
5
6
78function  letTest () {  let  x = 1;  if  (true ) {    let  x = 2;  // 不同的变量    console .log (x );  // 2  }  console .log (x );  // 1}
1
2
3
4
5
6
7
8// bad const  item = new  Object ();// good const  item = {};
1
2
3
4
5function  getKey (k ) {  return  `a key named ${k }`;}// bad const  obj = {  id : 5,  name : 'San Francisc
o',};obj [getKey ('enabled')] = true ;// good const  obj = {  id : 5,  name : 'San Francisco',  [getKey ('enabled')]: true ,};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
3.4 ⽤属性值缩写
如果属性名和属性值⼀样的话,可以缩写。
3.5 将你的所有缩写放在对象声明的前⾯
因为这样能更⽅便地知道有哪些属性⽤了缩写。// bad const  atom = {  value : 1,  addValue : function 
javascript的特性(value ) {    return  atom .value + value ;  },};// good const  atom = {  value : 1,  // 对象的⽅法  addValue (value ) {    return  atom .value + value ;  },};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18const  lukeSkywalker = 'Luke Skywalker';// bad const  obj = {  lukeSkywalker : lukeSkywalker ,};// good const  obj = {  lukeSkywalker ,};
1
2
3
4
5
6
7
8
9
10
11const  anakinSkywalker = 'Anakin Skywalker';const  lukeSkywalker = 'Luke Skywalker';// bad const  obj = {  episodeOne : 1,  twoJediWalkIntoACantina : 2,  lukeSkywalker ,  episodeThree : 3,  mayTheFourth : 4,  anakinSkywalker ,};// good const  obj = {  lukeSkywalker ,  anakinSkywalker ,  episodeOne : 1,  twoJediWalkIntoACantina : 2,  episodeThree : 3,  mayTheFourth : 4,};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
3.6 只对那些⽆效的标⽰使⽤引号 ''
通常我们认为这种⽅式主观上更易读。不仅优化了代码⾼亮,⽽且也更容易被许多 JS 引擎优化。
3.7 不要直接调⽤ Object.prototype 上的⽅法,如 hasOwnProperty 、propertyIsEnumerable 、isPrototypeOf 。为什么?在⼀些有问题的对象上,这些⽅法可能会被屏蔽掉,如:{ hasOwnProperty: false } 或空对象 ate(null)使⽤Object.prototype.hasOwnProperty.call()的原因:如果使⽤ ate(null) 创建的对象的原型是null ,⽽不是继承⾃Object.prototype ,所以没有hasOwnProperty ⽅法,调⽤只会得到undefined 。如果hasOwnProperty 在object 的原型链中被重写
如果hasOwnProperty 在object 上被重新声明
3.8 对象浅拷贝时,更推荐使⽤扩展运算符(即 … 运算符),⽽不是 Object.assign 。获取对象指定的⼏个属性时,⽤对象的 rest 解构运算符(即 … 运算符)更好。// bad const  bad = {  'foo': 3,  'bar': 4,  'data-blah': 5,};// good const  good = {  foo : 3,  bar : 4,  'data-blah': 5,};
1
2
3
4
5
6
7
8
9
10
11
12
13// 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 ));/* or */import  has from  'has'; // www.npmjs/package/has console .log (has (object , key ));
1
2
3
4
5
6
7
8
9
10
11
12// very bad ,拷贝引⽤地址,改变copy ,同时也会改变original 的值const  original = { a : 1, b : 2 };const  copy = Object .assign (original , { c : 3 }); delete  copy .a ; // so does this // bad ,只改变第⼀个对象,所以这⾥original 并没有改变const  original = { a : 1, b : 2 };const  copy = Object .assign ({}, original , { c : 3 }); // copy => { a: 1, b: 2, c: 3 }// good es6 扩展运算符 ...,返回⼀个新的对象,copy 是⼀个新的对象,在内存中另开辟了⼀个新的空间。const  original = { a : 1, b : 2 };// 浅拷贝const  copy = { ...original , c : 3 }; // copy => { a: 1, b: 2, c: 3 }// rest 解构运算符const  { a , ...noA } = copy ; // noA => { b: 2, c: 3 }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。