ES6 常用知识总结

ES6 常用知识总结
一、ES6简介
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

二、新特性

  1. let、const
    新特性注意点let1. 不存在变量提升 2. 暂时性死区(块级作用域) 3. 不允许重复声明const声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。 其只保证指针不发生改变,因此可以修改保存的对象的值

ES6 声明变量的6种方法:var function let const import class
// 取顶层对象
// 方法一

(typeof window !== 'undefined'
   ? window
   : (typeof process === 'object' &&
      typeof require === 'function' &&
      typeof global === 'object')
     ? global
     : this);

// 方法二
var getGlobal = function () {
  if (typeof self !== 'undefined') { return self; }
  if (typeof window !== 'undefined') { return window; }
  if (typeof global !== 'undefined') { return global; }
  throw new Error('unable to locate global object');
};
  1. 解构赋值
// 数组
let [x, y='b'] = ['a'] // x=''a, y='b'

// 对象
let { foo:f, bar:l=2 } = { foo: 'aaa', bar: undefined } // f,l才是变量名
f // aaa
l // 2

// 字符串
let {length: len} = ‘hello’
len // 5

// 数组和布尔值的解构赋值
// 只要等号右边的值不是对象或数组,就先将其转为对象。
// 由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。

// 函数参数解构
function move({x = 0, y = 0} = {}) {
return [x, y];
}
作用:
(1) 交换变量的值: [x, y] = [y, x];
(2) 从函数返回多个值: let { foo, bar } = example();
(3) 函数参数的定义: function f([x, y, z]) { … }
(4) 提取 JSON 数据: let { id, status, data: number } = jsonData;
(5) 函数参数的默认值
(6) 遍历 Map 结构const map = new Map(); map.set(‘first’, ‘hello’); map.set(‘second’, ‘world’); for (let [key, value] of map) { console.log(key + " is " + value); } // first is hello// second is world// 获取键名for (let [key] of map) { // … } // 获取键值for (let [,value] of map) { // … }
(7) 输入模块的指定方法: const { SourceMapConsumer, SourceNode } = require(“source-map”);
3. 字符串的扩展
(1) 字符的 Unicode 表示法
(2) 字符串的遍历接口
(3) 直接输入U+2028和U+2029
(4) Json的stringify()的改造
(5) 模版字符串

  1. 字符串的新增方法
    (1) String.fromCodePoint():String.fromCharCode(0x20BB7) // “ஷ”
    (2) String.raw():该方法返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,往往用于模板字符串的处理方法
    (3) codePointAt(): 能够正确处理 4 个字节储存的字符,返回一个字符的码点
    (4) normalize(): 用来将字符的不同表示方法统一为同样的形式,这称为 Unicode 正规化
    (5) includes():返回布尔值,表示是否找到了参数字符串/
    startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
    endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
    这三个方法都支持第二个参数,表示开始搜索的位置。
let s = 'Hello world!';

s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false

(6) ‘x’.repeat(3) // “xxx”
(7) padStart()、padEnd(): ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全
(8) trimStart()、trimEnd():消除字符串头、尾部的空格
(9) matchAll(): 返回一个正则表达式在当前字符串的所有匹配

  1. 正则的扩展

  2. 数值的扩展
    Number.isNaN()
    Number.isFinite()
    Number.isInteger():是否为整数
    Number.EPSILON:极小的常量
    Math.trunc(): 去除小数部分,返回整数部分
    Math.sign()判断正负、0,其他值返回NaN、指数运算符**,2**3 // 8

  3. 函数的扩展
    ES6 引入 rest 参数(形式为…变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

箭头函数
使用注意点:
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
不适用场合:
(1)定义对象的方法,且该方法内部包括thisconst cat = { lives: 9, jumps: () => { this.lives–; } } // 对象不构成单独的作用域,导致jumps箭头函数定义时的作用域就是全局作用域。
(2) 需要动态this的时候,也不应使用箭头函数var button = document.getElementById(‘press’); button.addEventListener(‘click’, () => { this.classList.toggle(‘on’); });
(3) 如果函数体很复杂,有许多行,或者函数内部有大量的读写操作,不单纯是为了计算值,这时也不应该使用箭头函数,而是要使用普通函数,这样可以提高代码可读性。
尾调用优化、尾递归
8. 数组的扩展
扩展运算符:任何定义了遍历器(Iterator)接口的对象(参阅 Iterator 一章),都可以用扩展运算符转为真正的数组,背后调用的是遍历器接口(Symbol.iterator)
Array.from(): 用于将两类对象转为真正的数组: 类似数组的对象(array-like object,比如 DOM 操作返回的 NodeList 集合,以及函数内部的arguments对象,本质是具有length属性)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)// 对于还没有部署该方法的浏览器,可以用Array.prototype.slice方法替代const toArray = (() => Array.from ? Array.from : obj => [].slice.call(obj) )(); // Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。 Array.from([1, 2, 3], (x) => x * x) // [1, 4, 9]
Array.of()方法用于将一组值,转换为数组。Array.of(3, 11, 8) // [3,11,8]
copyWithin(): [1, 2, 3, 4, 5].copyWithin(0, 3, 4) // 将3号位复制到0号位 [4, 2, 3, 4, 5]
find(): 用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined----[1, 5, 10, 15].find(function(value, index, arr) { return value > 9; }) // 10
findIndex()与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1,弥补了indexOf的不足,可以发现NaN[NaN].findIndex(y => Object.is(NaN, y)) // 0
fill():[‘a’, ‘b’, ‘c’].fill(7) // [7, 7, 7]new Array(3).fill(7) // [7, 7, 7]// 还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。 [‘a’, ‘b’, ‘c’].fill(7, 1, 2) // [‘a’, 7, ‘c’]
entries()、keys()、values(): keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历
includes(): 表示某个数组是否包含给定的值,与字符串的includes方法类似 [1, 2, NaN].includes(NaN) // true
flat(): 将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响[1, [2, [3]]].flat(Infinity) // [1, 2, 3]
flatMap(): 对原数组的每个成员执行一个函数(相当于执行Array.prototype.map()),然后对返回值组成的数组执行flat()方法。该方法返回一个新数组,不改变原数组。
9. 对象的扩展

let propKey = 'foo';
let obj = {
  [propKey]: true,
  ['a' + 'bc']: 123
};

属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object],这一点要特别小心。
属性的遍历方法有5种:
(1)for…in
for…in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
(2)Object.keys(obj)
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
this关键字总是指向函数所在的当前对象,ES6 又新增了另一个类似的关键字super,指向当前对象的原型对象
Object.is() :用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。不同之处只有两个:一是+0不等于-0,二是NaN等于自身。
Object.assign():用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。由于undefined和null无法转成对象,所以如果它们作为参数,就会报错。注意点:
(1)浅拷贝
(2)同名属性的替换
(3)数组的处理Object.assign([1, 2, 3], [4, 5]) // [4, 5, 3]
(4) 取值函数的处理:只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制。
Object.getOwnPropertyDescriptors() 返回一个对象,所有原对象的属性名都是该对象的属性名,对应的属性值就是该属性的描述对象
__proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf() 、Object.keys(),Object.values(),Object.entries() 、Object.fromEntries():Object.fromEntries([ [‘foo’, ‘bar’], [‘baz’, 42] ]) // { foo: “bar”, baz: 42 }
10. Symbol:
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
Symbol 值不能与其他类型的值进行运算,会报错。 但是,Symbol 值可以显式转为字符串。另外,Symbol 值也可以转为布尔值,但是不能转为数值。 可用来消除魔法字符串、模块的Singleton模式
11. Set、Map 数据结构

Set类似于数组,但是成员的值都是唯一的,没有重复的值。

const set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]
// 去除数组的重复成员
[...new Set(array)]
[...new Set('ababbc')].join('')
// "abc"
在 Set 内部,两个NaN是相等。另外,两个对象总是不相等的。
方法:
Set.prototype.add(value):添加某个值,返回 Set 结构本身。
Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。
Set.prototype.clear():清除所有成员,没有返回值。
Set.prototype.keys():返回键名的遍历器
Set.prototype.values():返回键值的遍历器
Set.prototype.entries():返回键值对的遍历器
Set.prototype.forEach():使用回调函数遍历每个成员

Set的遍历顺序就是插入顺序。这个特性有时非常有用,比如使用 Set 保存一个回调函数列表,调用时就能保证按照添加顺序调用。
WeakSet:WeakSet 结构与 Set 类似,也是不重复的值的集合。
但是,它与 Set 有两个区别:
(1)WeakSet 的成员只能是对象,而不能是其他类型的值。其次,WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。
(2)WeakSet 不能遍历,是因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在,很可能刚刚遍历结束,成员就取不到了。WeakSet 的一个用处,是储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏
Map: 类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。const m = new Map(); const o = {p: ‘Hello World’}; m.set(o, ‘content’) m.get(o) // “content” m.has(o) // true m.delete(o) // true m.has(o) // false
Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。
WeakMap: 首先,WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。其次,WeakMap的键名所指向的对象,不计入垃圾回收机制。
12. Proxy
在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写,很合适用来写 Web 服务的客户端。

  1. Reflect
    (1) 将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新方法将只部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法。
    (2) 修改某些Object方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false。
    (3) 让Object操作都变成函数行为。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)让它们变成了函数行为。
    (4)Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。

方法:

Reflect.apply(target, thisArg, args)
Reflect.construct(target, args)
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.defineProperty(target, name, desc)
Reflect.deleteProperty(target, name)
Reflect.has(target, name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)
  1. Promise
    特点:
    (1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
    (2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
    缺点:
    首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
    promise
    .then(result => {···})
    .catch(error => {···})
    .finally(() => {···});
    Promise.all(): 用于将多个 Promise 实例,包装成一个新的 Promise 实例。const p = Promise.all([p1, p2, p3]);
    p的状态由p1、p2、p3决定,分成两种情况。
    (1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
    (2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
    注意,如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。
    Promise.race(): const p = Promise.race([p1, p2, p3]);只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
    Promise.resolve()、Promis.reject()、Promise.try()
  2. Iterator
    任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。

作用:
(1)为各种数据结构,提供一个统一的、简便的访问接口;
(2)使得数据结构的成员能够按某种次序排列;
(3)ES6 创造了一种新的遍历命令for…of循环,Iterator 接口主要供for…of消费。

  1. Generator
    Generator 函数是一个普通函数,但是有两个特征:
    (1)function关键字与函数名之间有一个星号;
    (2)函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。
    调用 Generator 函数,返回一个遍历器对象,代表 Generator 函数的内部指针。以后,每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield表达式后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。
    异步编程:
    (1)回调函数
    (2)事件监听
    (3)发布/订阅
    (4)Promise 对象
    (5)Generator 函数
  2. async
    async函数对 Generator 函数的改进,体现在以下四点。
    (1)内置执行器。
    (2)更好的语义。
    (3)更广的适用性: co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
const fn = async () =>{
  const res1 = await fn1();
  const res2 = await fn2();
  console.log(res1);// 1
  console.log(res2);// 2
}

(4)返回值是 Promise。
3. Class
与 ES5 一样,在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。类的属性名,可以采用表达式。
父类Foo有一个静态方法,子类Bar可以调用这个方法。 静态方法也是可以从super对象上调用的。
为class加了私有属性。方法是在属性名之前,使用#表示。
extends 继承,子类的构造函数必须执行一次super函数
4. Module
import、export
ES6模块的好处:
(1)不再需要UMD模块格式了,将来服务器和浏览器都会支持 ES6 模块格式。目前,通过各种工具库,其实已经做到了这一点。
(2)将来浏览器的新 API 就能用模块格式提供,不再必须做成全局变量或者navigator对象的属性。
(3)不再需要对象作为命名空间(比如Math对象),未来这些功能可以通过模块提供。
import(): 类似于 Node 的require方法,区别主要是前者是异步加载,后者是同步加载。
(1)按需加载。(2)条件加载(3)动态的模块路径
defer是“渲染完再执行”,async是“下载完就执行”
浏览器加载 ES6 模块,也使用

你会用ES6?

一、关于取值的吐槽
取值在程序中非常常见,比如从对象obj中取值。

const obj = {
    a:1,
    b:2,
    c:3,
    d:4,
    e:5,
}

复制代码
吐槽:

const a = obj.a;
const b = obj.b;
const c = obj.c;
const d = obj.d;
const e = obj.e;

或者
const f = obj.a + obj.d;
const g = obj.c + obj.e;

吐槽:“不会用ES6的解构赋值来取值吗?5行代码用1行代码搞定不香吗?直接用对象名加属性名去取值,要是对象名短还好,很长呢?搞得代码中到处都是这个对象名。”
改进:

const {a,b,c,d,e} = obj;
const f = a + d;
const g = c + e;

反驳
不是不用ES6的解构赋值,而是服务端返回的数据对象中的属性名不是我想要的,这样取值,不是还得重新创建个遍历赋值。
吐槽
看来你对ES6的解构赋值掌握的还是不够彻底。如果想创建的变量名和对象的属性名不一致,可以这么写:
const {a:a1} = obj;
console.log(a1);// 1
复制代码
补充
ES6的解构赋值虽然好用。但是要注意解构的对象不能为undefined、null。否则会报错,故要给被解构的对象一个默认值。

const {a,b,c,d,e} = obj || {};

二、关于合并数据的吐槽
比如合并两个数组,合并两个对象。

const a = [1,2,3];
const b = [1,5,6];
const c = a.concat(b);//[1,2,3,1,5,6]

const obj1 = {
  a:1,
}
const obj2 = {
  b:1,
}
const obj = Object.assign({}, obj1, obj2);//{a:1,b:1}

ES6的扩展运算符是不是忘记了,还有数组的合并不考虑去重吗?
改进

const a = [1,2,3];
const b = [1,5,6];
const c = [...new Set([...a,...b])];//[1,2,3,5,6]

const obj1 = {
  a:1,
}
const obj2 = {
  b:1,
}
const obj = {...obj1,...obj2};//{a:1,b:1}

三、关于拼接字符串的吐槽

const name = '小明';
const score = 59;
let result = '';
if(score > 60){
  result = `${name}的考试成绩及格`; 
}else{
  result = `${name}的考试成绩不及格`; 
}

像你们这样用ES6字符串模板,还不如不用,你们根本不清楚在 中 可 以 做 什 么 操 作 。 在 {}中可以做什么操作。在 {}中可以放入任意的JavaScript表达式,可以进行运算,以及引用对象属性。
改进

const name = '小明';
const score = 59;
const result = `${name}${score > 60?'的考试成绩及格':'的考试成绩不及格'}`;

四、关于if中判断条件的吐槽

if(
    type == 1 ||
    type == 2 ||
    type == 3 ||
    type == 4 ||
){
   //...
}

ES6中数组实例方法includes会不会使用呢?
改进

const condition = [1,2,3,4];

if( condition.includes(type) ){
   //...
}

五、关于列表搜索的吐槽
在项目中,一些没分页的列表的搜索功能由前端来实现,搜索一般分为精确搜索和模糊搜索。搜索也要叫过滤,一般用filter来实现。
const a = [1,2,3,4,5];
const result = a.filter(
item =>{
return item === 3
}
)
如果是精确搜索不会用ES6中的find吗?性能优化懂么,find方法中找到符合条件的项,就不会继续遍历数组。
改进
const a = [1,2,3,4,5];
const result = a.find(
item =>{
return item === 3
}
)

六、关于扁平化数组的吐槽
一个部门JSON数据中,属性名是部门id,属性值是个部门成员id数组集合,现在要把有部门的成员id都提取到一个数组集合中。

const deps = {
'采购部':[1,2,3],
'人事部':[5,8,12],
'行政部':[5,14,79],
'运输部':[3,64,105],
}
let member = [];
for (let item in deps){
    const value = deps[item];
    if(Array.isArray(value)){
        member = [...member,...value]
    }
}
member = [...new Set(member)]

获取对象的全部属性值还要遍历吗?Object.values忘记了吗?还有涉及到数组的扁平化处理,为啥不用ES6提供的flat方法呢,还好这次的数组的深度最多只到2维,还要是遇到4维、5维深度的数组,是不是得循环嵌套循环来扁平化?
改进
const deps = {
‘采购部’:[1,2,3],
‘人事部’:[5,8,12],
‘行政部’:[5,14,79],
‘运输部’:[3,64,105],
}
let member = Object.values(deps).flat(Infinity);

其中使用Infinity作为flat的参数,使得无需知道被扁平化的数组的维度。
补充
flat方法不支持IE浏览器。
七、关于获取对象属性值的吐槽
const name = obj && obj.name;

ES6中的可选链操作符会使用么?
改进
const name = obj?.name;

八、关于添加对象属性的吐槽
当给对象添加属性时,如果属性名是动态变化的,该怎么处理。
let obj = {};
let index = 1;
let key = topic${index};
obj[key] = ‘话题内容’;

吐槽
为何要额外创建一个变量。不知道ES6中的对象属性名是可以用表达式吗?
改进
let obj = {};
let index = 1;
obj[topic${index}] = ‘话题内容’;

九、关于输入框非空的判断
在处理输入框相关业务时,往往会判断输入框未输入值的场景。
if(value !== null && value !== undefined && value !== ‘’){
//…
}
ES6中新出的空值合并运算符了解过吗,要写那么多条件吗?
if(value??’’ !== ‘’){
//…
}
复制代码
十、关于异步函数的吐槽
异步函数很常见,经常是用 Promise 来实现。
const fn1 = () =>{
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 300);
});
}
const fn2 = () =>{
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
}, 600);
});
}
const fn = () =>{
fn1().then(res1 =>{
console.log(res1);// 1
fn2().then(res2 =>{
console.log(res2)
})
})
}
如果这样调用异步函数,不怕形成地狱回调啊!
改进

const fn = async () =>{
  const res1 = await fn1();
  const res2 = await fn2();
  console.log(res1);// 1
  console.log(res2);// 2
}

补充
但是要做并发请求时,还是要用到Promise.all()。

const fn = () =>{
   Promise.all([fn1(),fn2()]).then(res =>{
       console.log(res);// [1,2]
   }) 
}

如果并发请求时,只要其中一个异步函数处理完成,就返回结果,要用到Promise.race()。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端壹栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值