JavaScript速查表

本文为作者原创,转载请注明出处:https://www.cnblogs.com/zhaoqingqing/p/18403172



JavaScript速查表

  • 本手册绝大部分内容是从Airbnb JavaScript Style Guide精简整理,将开发者们都明确的操作去掉,目的为了就是更快的速查。
    此处为源地址

  • 译制:HaleNing

目录#

基础知识#

类型#

  • 基本类型
    最新的 ECMAScript 标准定义了 8 种数据类型,分别是
    • string
    • number
    • bigint
    • boolean
    • null
    • undefined
    • symbol (ECMAScript 2016新增)

所有基本类型的值都是不可改变的。但需要注意的是,基本类型本身和一个赋值为基本类型的变量的区别。变量会被赋予一个新值,而原值不能像数组、对象以及函数那样被改变。

  • 引用类型
    • Object(包含普通对象-Object,数组对象-Array,正则对象-RegExp,日期对象-Date,数学函数-Math,函数对象-Function)
Copy
使用 typeof 运算符检查: undefinedtypeof instance === "undefined" Booleantypeof instance === "boolean" Numbertypeof instance === "number" Stringtypeof instance === "string BigInt:typeof instance === "bigint" Symbol :typeof instance === "symbol" null:typeof instance === "object"。 Object:typeof instance === "object"

引用#

推荐常量赋值都使用const, 值可能会发生改变的变量赋值都使用 let

为什么?let const 都是块级作用域,而 var是函数级作用域

Copy
// bad var count = 1; if (true) { count += 1; } // good, use the let and const let count = 1; const pi =3.14; if (true) { count += 1; }

对象#

  • 使用字面语法创建对象:

    Copy
    // bad const item = new Object(); // good const item = {};
  • 在创建具有动态属性名称的对象时使用属性名称:

    Copy
    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, };
  • 属性值简写,并且推荐将缩写 写在前面 :

    Copy
    const lukeSkywalker = 'Luke Skywalker'; //常量名就是你想设置的属性名 // bad const obj = { lukeSkywalker: lukeSkywalker, }; // good const obj = { lukeSkywalker, }; const anakinSkywalker = 'Anakin Skywalker'; const lukeSkywalker = 'Luke Skywalker'; // good const obj = { lukeSkywalker, anakinSkywalker, episodeOne: 1, twoJediWalkIntoACantina: 2, episodeThree: 3, mayTheFourth: 4, };
  • 不要直接调用 Object.prototype上的方法,如 hasOwnPropertypropertyIsEnumerableisPrototypeOf

    为什么?在一些有问题的对象上,这些方法可能会被屏蔽掉,如:{ hasOwnProperty: false } 或空对象 Object.create(null)

    Copy
    // 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'; // https://www.npmjs.com/package/has console.log(has(object, key));
  • 对象拷贝时,推荐使用...运算符来代替Object.assign, 获取大对象的多个属性时,也推荐使用...运算符

    Copy
    // very bad, 因为line2的操作更改了original const original = { a: 1, b: 2 }; const copy = Object.assign(original, { c: 3 }); // 将不需要的属性删除了 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 使用 es6 扩展运算符 ... 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 }

数组#

  • 用扩展运算符做数组浅拷贝,类似上面的对象浅拷贝:

    Copy
    // bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i += 1) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];
  • ... 运算符而不是 Array.from 来将一个可迭代的对象转换成数组:

    Copy
    const foo = document.querySelectorAll('.foo'); // good const nodes = Array.from(foo); // best const nodes = [...foo];
  • 使用 Array.from 而不是 ... 运算符去做 map 遍历。 因为这样可以避免创建一个临时数组:

    Copy
    // bad const baz = [...foo].map(bar); // good const baz = Array.from(foo, bar);
  • 如果一个数组有很多行,在数组的 [ 后和 ] 前断行 :

    Copy
    // good const arr = [[0, 1], [2, 3], [4, 5]]; const objectInArray = [ { id: 1, }, { id: 2, }, ]; const numberInArray = [ 1, 2, ];

解构#

  • 用对象的解构赋值来获取和使用对象某个或多个属性值:

    Copy
    // 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}`; }
  • 数组解构:

    Copy
    const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; const four = arr[3]; // good const [first, second, _,four] = arr;
  • 多个返回值用对象的解构,而不是数组解构:

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

字符串#

  • 当需要动态生成字符串时,使用模板字符串而不是字符串拼接:

    Copy
    // bad function sayHi(name) { return 'How are you, ' + name + '?'; } // bad function sayHi(name) { return ['How are you, ', name, '?'].join(); } // good 可读性比上面更强 function sayHi(name) { return `How are you, ${name}?`; }
  • 永远不要使用 eval(),该方法有太多漏洞。

变量#

  • 不要使用链式变量赋值

因为会产生隐式的全局变量

Copy
// bad (function example() { // JavaScript interprets this as // let a = ( b = ( c = 1 ) ); // The let keyword only applies to variable a; variables b and c become // global variables. 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 // the same applies for `const`
  • 不要使用一元自增自减运算符(++--

    根据 eslint 文档,一元增量和减量语句受到自动分号插入的影响,并且可能会导致应用程序中的值递增或递减的静默错误。 使用 num + = 1 而不是 num ++num ++ 语句也是含义清晰的。

Copy
// bad const 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 const 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;

属性#

  • 访问属性时使用点符号
Copy
const luke = { jedi: true, age: 28, }; // bad const isJedi = luke['jedi']; // good const isJedi = luke.jedi;
  • 根据表达式访问属性时使用[]
Copy
const luke = { jedi: true, age: 28, }; function getProp(prop) { return luke[prop]; } const isJedi = getProp('je'+'di');

测试#

  • 无论用哪个测试框架,都需要写测试。
  • 尽量去写很多小而美的函数,减少突变的发生
  • 小心 stub 和 mock —— 这会让你的测试变得容易出现问题。
  • 100% 测试覆盖率是我们努力的目标,即便实际上很少达到。
  • 每当你修了一个 bug, 都要尽量写一个回归测试。 如果一个 bug 修复了,没有回归测试,很可能以后会再次出问题。

公共约束#

注释#

  • 多行注释用 /** ... */
Copy
// bad // make() returns a new element // based on the passed in tag name // // @param {String} tag // @return {Element} element function make(tag) { // ... return element; } // good /** * make() returns a new element * based on the passed-in tag name */ function make(tag) { // ... return element; }
  • 单行注释用 //
Copy
// 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; }
  • // FIXME: 给问题注释,用 // TODO: 去注释待办

分号#

为什么?当 JavaScript 遇到没有分号结尾的一行,它会执行 自动插入分号 这一规则来决定行末是否加分号。如果 JavaScript 在你的断行里错误的插入了分号,就会出现一些古怪的行为。显式配置代码检查去检查没有带分号的地方可以帮助你防止这种错误。

Copy
// 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'; }

命名规范#

  • export default 导出模块A,则这个文件名也叫 A.*import 时候的参数也叫 A :
Copy
// 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一个函数时,函数名用小驼峰,文件名和函数名一致, export 一个结构体/类/单例/函数库/对象 时用大驼峰。
Copy
function makeStyleGuide() { // ... } export default makeStyleGuide; const AirbnbStyleGuide = { es6: { } }; export default AirbnbStyleGuide;

标准库#

标准库中包含一些由于历史原因遗留的工具类

  • Number.isNaN 代替全局的 isNaN:

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

Copy
// bad isFinite('2e3'); // true // good Number.isFinite('2e3'); // false Number.isFinite(parseInt('2e3', 10)); // true

类与函数#

函数#

  • 使用命名函数表达式而不是函数声明

    为什么?这是因为函数声明会发生提升,这意味着在一个文件里函数很容易在其被定义之前就被引用了。这样伤害了代码可读性和可维护性。如果你发现一个函数又大又复杂,且这个函数妨碍了这个文件其他部分的理解性,你应当单独把这个函数提取成一个单独的模块。不管这个名字是不是由一个确定的变量推断出来的,别忘了给表达式清晰的命名(这在现代浏览器和类似 babel 编译器中很常见)。这消除了由匿名函数在错误调用栈产生的所有假设。 (讨论)

    Copy
    // bad function foo() { // ... } // bad const foo = function () { // ... }; // good // lexical name distinguished from the variable-referenced invocation(s) // 函数表达式名和声明的函数名是不一样的 const short = function longUniqueMoreDescriptiveLexicalFoo() { // ... };
  • 把立即执行函数包裹在圆括号里:

    立即执行函数:Immediately Invoked Function expression = IIFE。 为什么?因为这样使代码读起来更清晰(译者注:我咋不觉得)。 另外,在模块化世界里,你几乎用不着 IIFE。

    Copy
    // immediately-invoked function expression (IIFE) ( ()=> { console.log('Welcome to the Internet. Please follow me.'); }() );
  • 不要用 arguments 命名参数。他的优先级高于每个函数作用域自带的 arguments 对象,这会导致函数自带的 arguments 值被覆盖:

    Copy
    // bad function foo(name, options, arguments) { // ... } // good function foo(name, options, args) { // ... }
  • 用默认参数语法而不是在函数里对参数重新赋值

    Copy
    // really bad function handleThings(opts) { // 如果 opts 的值为 false, 它会被赋值为 {} // 虽然你想这么写,但是这个会带来一些微妙的 bug。 opts = opts || {}; // ... } // still bad function handleThings(opts) { if (opts === void 0) { opts = {}; } // ... } // good function handleThings(opts = {}) { // ... }
  • 把默认参数赋值放在最后面

    Copy
    // bad function handleThings(opts = {}, name) { // ... } // good function handleThings(name, opts = {}) { // ... }
  • 不要修改参数,也不要重新对函数参数赋值:

    容易导致bug,另外重新对参数赋值也会导致优化问题。

    Copy
    // 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) { // ... }

箭头函数#

  • 当需要使用箭头函数的时候,使用它,但是不要滥用

    当函数逻辑复杂时,不推荐使用箭头函数,而是单独抽出来放在一个函数里。

    Copy
    // 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; });
  • 避免箭头函数与比较操作符混淆

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

类与构造函数#

  • 使用class 语法。避免直接操作 prototype

    Copy
    // 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 实现继承:

    为什么?它是一种内置的方法来继承原型功能而不破坏 instanceof

    Copy
    // 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 来实现链式调用

Copy
// 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() 方法是可以的,但需要保证它可以正常工作
Copy
class Jedi { constructor(options = {}) { this.name = options.name || 'no name'; } getName() { return this.name; } toString() { return `Jedi - ${this.getName()}`; } }
  • 如果没有特别定义,类有默认的构造方法。一个空的构造函数或只是代表父类的构造函数是不需要写的。
Copy
// bad class Jedi { constructor() {} getName() { return this.name; } } // bad class Rey extends Jedi { // 这种构造函数是不需要写的 constructor(...args) { super(...args); } } // good class Rey extends Jedi { constructor(...args) { super(...args); this.name = 'Rey'; } }

模块#

  • 使用(import/export)模块
Copy
// bad const AirbnbStyleGuide = require('./AirbnbStyleGuide'); module.exports = AirbnbStyleGuide.es6; // ok import AirbnbStyleGuide from './AirbnbStyleGuide'; export default AirbnbStyleGuide.es6; // best import { es6 } from './AirbnbStyleGuide'; export default es6;
  • 不要导出可变的东西:

变化通常都是需要避免,特别是当你要输出可变的绑定。虽然在某些场景下可能需要这种技术,但总的来说应该导出常量。

Copy
// bad let foo = 3; export { foo } // good const foo = 3; export { foo }
  • import JavaScript文件不用包含扩展名
Copy
// bad import foo from './foo.js'; import bar from './bar.jsx'; import baz from './baz/index.jsx'; // good import foo from './foo'; import bar from './bar'; import baz from './baz';

迭代器与生成器#

  • 不要用迭代器。使用 JavaScript 高级函数代替 for-infor-of

    用数组的这些迭代方法: map() / every() / filter() / find() / findIndex() / reduce() / some() / ... , 对象的这些方法 Object.keys() / Object.values() / Object.entries() 得到一个数组,就能去遍历对象。

    Copy
    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);

提升#

  • var 声明会被提前到离他最近的作用域的最前面,但是它的赋值语句并没有提前。constlet 被赋予了新的概念 暂时性死区 (TDZ)。 重要的是要知道为什么 typeof 不再安全
Copy
// 我们知道这个不会工作,假设没有定义全局的 notDefined function example() { console.log(notDefined); // => throws a ReferenceError } // 在你引用的地方之后声明一个变量,他会正常输出是因为变量提升。 // 注意: declaredButNotAssigned 的值 true 没有被提升。 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; }
  • 已命名函数表达式提升他的变量名,不是函数名或函数体
Copy
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'); }; } // 函数名和变量名一样是也如此。 function example() { console.log(named); // => undefined named(); // => TypeError named is not a function var named = function named() { console.log('named'); }; }

比较运算符与相等#

  • ===!== 严格比较而不是 ==!=

  • 条件语句,例如if语句使用coercion与tobooleant抽象方法评估它们的表达式,始终遵循这些简单的规则:

    • Objects evaluate to true
    • Undefined evaluates to false
    • Null evaluates to false
    • Booleans evaluate to the value of the boolean
    • Numbers evaluate to false if +0, -0, or NaN, otherwise true
    • Strings evaluate to false if an empty string '', otherwise true
Copy
if ([0] && []) { // true // an array (even an empty one) is an object, objects will evaluate to true }
  • 三元表达式不应该嵌套,尽量保持单行表达式
Copy
// 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;

事件#

  • 当把数据载荷传递给事件时(例如是 DOM 还是像 Backbone 这样有很多属性的事件)。这使得后续的贡献者(程序员)向这个事件添加更多的数据时不用去找或者更新每个处理器。
Copy
// bad $(this).trigger('listingUpdated', listing.id); // ... $(this).on('listingUpdated', (e, listingID) => { // do something with listingID });

类型转换与强制转换#

  • 字符串
Copy
// => this.reviewScore = 9; // bad const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string" // bad const totalScore = this.reviewScore + ''; // bad const totalScore = this.reviewScore.toString(); // 不保证返回 string // good const totalScore = String(this.reviewScore);
  • 数字: 用 Number 做类型转换,parseInt 转换 string 应总是带上进制位
Copy
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);
  • 移位运算要小心

    移位运算对大于 32 位的整数会导致意外行为。Discussion. 最大的 32 位整数是 2,147,483,647:

Copy
2147483647 >> 0 //=> 2147483647 2147483648 >> 0 //=> -2147483648 2147483649 >> 0 //=> -2147483647

推荐资源#

  • 网站:

    • MDN: 不管你是仅仅开始入门、学过一点基础或者是个网站开发老手,你都能在这里找到有用的资源。
    • JS周刊 : 你可以在这里,接收到JS社区里最新的动态,其他开发者编写的优秀工具,阅读优秀的文章。
    • 印记中文 : JS及其前端领域的文档集合。
  • 书籍(为了尊重作者的版权,下列书籍仅开源书籍提供链接):

作者:赵青青   一名在【网易游戏】做游戏开发的程序员,擅长Unity3D,游戏开发,.NET等领域。
本文版权归作者和博客园共有,欢迎转载,转载之后请务必在文章明显位置标出原文链接和作者,谢谢。
如果本文对您有帮助,请点击【推荐】您的赞赏将鼓励我继续创作!想跟我一起进步么?那就【关注】我吧。
posted @   赵青青  阅读(147)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· [翻译] 为什么 Tracebit 用 C# 开发
· 腾讯ima接入deepseek-r1,借用别人脑子用用成真了~
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· DeepSeek崛起:程序员“饭碗”被抢,还是职业进化新起点?
· RFID实践——.NET IoT程序读取高频RFID卡/标签
历史上的今天:
2021-09-08 python代码检查工具(静态代码审查)
2021-09-08 各大安卓模拟器的adb端口和使用对比
2014-09-08 DoTween(HOTween V2) 教程
2013-09-08 Unity制作FPS Demo
CONTENTS
点击右上角即可分享
微信分享提示