Airbnb JavaScript style guide

Posted by JustinM01 on Fri, 11 Feb 2022 16:50:47 +0100

1. Type

1.1 basic type: you can get the value of basic type directly. (direct access)

string,number,boolean,null,undefined,symbol,bigint.

  • symbol is the original data type newly introduced by ES6, which represents a unique value. The reason for its introduction is to fundamentally prevent the conflict of object attribute names, so it is used as the identifier of object attributes.
  • BigInt is created by appending n to the end of an integer or calling a constructor. BigInt can represent an integer of any size.
const foo = 1;
let bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9

Because Symbols and BigInts cannot be correctly polyfill. Therefore, they should not be used in environments or browsers that cannot natively support these types.

Understand this sentence:

polyfill uses JavaScript to implement some native API s that browsers do not support.
For example, querySelectorAll is a native Web API supported by many modern browsers, but some old browsers do not support it. Suppose someone has written a library. As long as you use this library, you can use document in the old browser querySelectorAll is used in the same way as the native API of modern browsers. Then this library can be called Polyfill or Polyfiller. A Polyfill is used to smooth the gap between new and old browser standards and native APIs.

At present, the support of BigInt browser is not ideal. Only Chrome supports well, but other browsers do not support well. Unlike other new JavaScript features, BigInt cannot be well compiled into ES5. Because BigInt modifies the working behavior of operators, these behaviors cannot be directly converted by polyfill.
If you want to use BigInt, at present, a better choice is to use JSBI library. Pure JS implements BigInt. One advantage of using JSBI is that once the browser supports it, there is no need to rewrite the code. Instead, you can use the babel plug-in to automatically compile JSBI code into native BigInt code.

Babel It's a JavaScript compiler. Put him in the latest version javascript Compile into the current executable version, that is, use babel You can let us use these latest tools freely in the current project es6,even to the extent that es7 Grammar of.

babel effect:
	(1)Syntax transformation (parsing high-level syntax into currently available implementations)
	(2)Source code conversion(codemods)
    (3)Polyfill Missing features in the target environment (e.g core-js Third party polyfill)
    
babel-core: Babel The core of the compiler, Babel Only new ones are converted by default javascript Syntax without converting new API,such as Iterator,Generator,Set,Maps,Proxy,Reflect,Symbol,Promise And other global objects, so convert these new objects API A gasket library is required polyfill. 

1.2 complex type: complex type assignment is to obtain the value of its reference.

object,array,function

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

bar[0] = 9;

console.log(foo[0], bar[0]); // => 9, 9

2. Reference

2.1 const is used for all assignments, and var is avoided. eslint: prefer-const, no-const-assign

2.2 if you have to re assign values to parameters, use let instead of var. eslint: no-var

  • Declaration creates a value with const instead of var, which ensures that the value you declare will not be redefined
    When multiple people develop a project, for example, they all define a variable a, but their respective purposes are different. The later defined a will overwrite the previously defined a.

2.3 both let and const are block level scopes

// Both const and let exist only in the block level scope in which they are defined.
{
  let a = 1;
  const b = 1;
}
console.log(a); 	// Error a undefined
console.log(b); 	// report errors

2.4 thinking: why use let instead of var

There is variable promotion in JS (variable promotion: the working mode of JavaScript engine is to parse the code, obtain all declared variables, and then run line by line. As a result, all variable declaration statements will be promoted to the head of the code, which is called variable promotion. (hanging keywords with var and function will lead to variable promotion)
Variable promotion will bring some problems:

1. Variables may be overwritten
var myname = 1;
function showName() {
  //var myname (variable promotion operation)
  console.log(myname);    //undefined
  if(0) {
  	var myname = 2;
  }
  console.log(myname);    //undefined
}
showName();
2. Variables that should have been destroyed were not destroyed
function foo(){
  // Var I (variable promotion)
  for (var i = 0; i < 7; i++) {
  }
  console.log(i);   //7
}
foo()

During the execution context creation phase, the variable i has been promoted, so when the for loop ends, the variable i is not destroyed.

The let and const keywords introduced in ES6 are to solve the problems caused by variable promotion.

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // Same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

There are two places where the variable x is defined. The first place is at the top of the function block and the second place is inside the if block. Since the scope of var is the whole function, only one variable x is finally generated in the compilation stage. All assignment operations to X in the function will directly change the x value in the variable environment.

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // Different variables
    console.log(x);  // 2
  }
  console.log(x);  // 1
}

let supports block level scope. The variables defined inside the code block cannot be accessed outside the code block, and the variables defined in the code block will be destroyed after the code in the code block is executed.

3. Object

3.1 creating objects with literals

Use {} instead of the new keyword.

// bad
const item = new Object();

// good
const item = {};

3.2 create an object with a dynamic attribute name using the calculated attribute name

When creating an object with dynamic attribute name, it is represented by calculated attribute name, so that all attributes can be written in the same place when creating the object.

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

// bad
const obj = {
  id: 5,
  name: 'San Francisco',
};
obj[getKey('enabled')] = true;

// good
const obj = {
  id: 5,
  name: 'San Francisco',
  [getKey('enabled')]: true,
};

3.3 object method abbreviation

// bad
const atom = {
  value: 1,

  addValue: function (value) {
    return atom.value + value;
  },
};

// good
const atom = {
  value: 1,

  // Object method
  addValue(value) {
    return atom.value + value;
  },
};

3.4 attribute value abbreviation

If the attribute name is the same as the attribute value, it can be abbreviated.

const lukeSkywalker = 'Luke Skywalker';

// bad
const obj = {
  lukeSkywalker: lukeSkywalker,
};

// good
const obj = {
  lukeSkywalker,
};

3.5 put all your abbreviations before the object declaration

This makes it easier to know which attributes are abbreviated.

const 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,
};

3.6 use quotation marks' 'only for those invalid marks

Usually we think this way is subjectively easier to read. It not only optimizes code highlighting, but also is easier to be optimized by many JS engines.

// bad
const bad = {
  'foo': 3,
  'bar': 4,
  'data-blah': 5,
};

// good
const good = {
  foo: 3,
  bar: 4,
  'data-blah': 5,
};

3.7 do not directly call object Methods on prototype, such as hasOwnProperty, propertyIsEnumerable, isPrototypeOf.

Why? On some problematic objects, these methods may be masked, such as: {hasOwnProperty: false} or empty object create(null)

// bad
console.log(object.hasOwnProperty(key));

// good
console.log(Object.prototype.hasOwnProperty.call(object, key));

// best
const has = Object.prototype.hasOwnProperty; // Cache once within the scope of the module.
console.log(has.call(object, key));
/* or */
import has from 'has'; // https://www.npmjs.com/package/has
console.log(has(object, key));

Use object prototype. hasOwnProperty. Reason for call():

  • If you use object Create (null) the prototype of the created object is null, not inherited from object Prototype, so there is no hasOwnProperty method, and the call will only get undefined.
  • If hasOwnProperty is rewritten in the prototype chain of object
  • If hasOwnProperty is redeclared on the object

3.8 for shallow copy of objects, the extension operator (i.e. the... Operator) is more recommended than object assign. When obtaining several properties specified by the object, it is better to use the rest deconstruction operator of the object (i.e. the... Operator).

// very bad, copy the reference address, change copy, and change the value of original
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); 
delete copy.a; // so does this

// bad, only the first object is changed, so the original is not changed here
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }

// good es6 extension operator, Returns a new object. copy is a new object, which opens up a new space in memory.
const original = { a: 1, b: 2 };
// Shallow copy
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }

// rest deconstruction operator
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }

4. Array

4.1 creating arrays with literal values

No new, use []

// bad
const items = new Array();

// good
const items = [];

4.2 use Array#push instead of adding a value directly to the array

const someStack = [];

// bad
someStack[someStack.length] = 'abracadabra';

// good
someStack.push('abracadabra');

Reason: vue rewrites the push method for the array. Only by updating the array with push can vue listen and update the view. Conversely, using array subscripts to modify the array cannot trigger the update of the view.

4.3 shallow copy of array with extension operator

// bad
const len = items.length;
const itemsCopy = [];
let i;

for (i = 0; i < len; i += 1) {
  itemsCopy[i] = items[i];
}

// good
const itemsCopy = [...items];

4.4 use the... Operator instead of array From to convert an iteratable object into an array

Iteratable object: if an object or any object in its prototype chain has symbol The attribute of the iterator key, then this object is an iteratable object.
Iteratable objects are: String, Array, Map (Map object saves key value pairs and can remember the original insertion order of keys) and Set (Set object allows you to store unique values of any type, whether original values or object references).

Array. The from () method creates a new, shallow copy of an array instance of a similar array or iteratable object.

const foo = document.querySelectorAll('.foo');

// good
const nodes = Array.from(foo);

// best
const nodes = [...foo];

4.5 use array From converts an array like object into an array

Class array: there are index and length attributes, but there may be no other methods of native array.

const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 };

// bad, which is equivalent to intercepting all the parameters and returning them to a new array. The essence is that the arrLike object uses the slice method of the array
const arr = Array.prototype.slice.call(arrLike);

// good
const arr = Array.from(arrLike);

4.6 use array From instead of... Operator to do map traversal. This avoids creating a temporary array

// bad
const baz = [...foo].map(bar);

// good,Array.from can receive the second parameter, which is similar to the map method of the array. Each element in the array will execute the callback function.
const baz = Array.from(foo, bar);

4.7 use the return statement in the callback function of the array method. If the function body consists of a statement that returns an expression and the expression has no side effects, return can be ignored at this time

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

// The good function has only one statement
[1, 2, 3].map(x => x + 1);

// bad - no return value because acc becomes undefined after the first iteration.
//reduce, execute a function provided by us for each element in the array, and the results are summarized into a single return value. acc is the accumulator. When the callback function was called last time, the value returned by the callback function.
[[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
  const flatten = acc.concat(item);
  acc[index] = flatten;
});

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

// bad
inbox.filter((msg) => {
  const { subject, author } = msg;
  if (subject === 'Mockingbird') {
    return author === 'Harper Lee';
  } else {
    return false;
  }
});

// good
inbox.filter((msg) => {
  const { subject, author } = msg;
  if (subject === 'Mockingbird') {
    return author === 'Harper Lee';
  }

  return false;
});

4.8 if an array has many rows, break the rows before and after the array. See the following example:

// bad
const arr = [
  [0, 1], [2, 3], [4, 5],
];

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

const numberInArray = [
  1, 2,
];

// good
const arr = [[0, 1], [2, 3], [4, 5]];

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

const numberInArray = [
  1,
  2,
];

To be added

reference resources:
1. polyfill---- https://blog.csdn.net/weixin_33884611/article/details/88912958
2. Variable lifting---- https://blog.csdn.net/qq_42872073/article/details/110489515?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164437829116780271988463%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164437829116780271988463&biz_id=0&utm_medium=distribute.pc_search_result.none -task-blog-2allfirst_ rank_ ecpm_ v1~rank_ v31_ ecpm-4-110489515. first_ rank_ v2_ pc_ rank_ v29&utm_ Defects of term = JS + var & SPM = 1018.2226.3001.4187
3. Extend operator and object The difference between assign---- https://blog.csdn.net/weixin_39647035/article/details/103233926?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164447964616781683919322%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164447964616781683919322&biz_id=0&utm_medium=distribute.pc_search_result.none -task-blog-2allfirst_ rank_ ecpm_ v1~rank_ v31_ ecpm-7-103233926. first_ rank_ v2_ pc_ rank_ v29&utm_ term=Object. Difference between assign and extension operator & SPM = 1018.2226.3001.4187

Topics: Javascript