JavaScript相关面试题5:ES7-ES12

简介: 使用场景loading关闭需要每次发送请求,都会有loading提示,请求发送完毕,就需要关闭loading提示框,不然界面就无法被点击。不管请求成功或是失败,这个loading都需要关闭掉,这时把关闭loading的代码写在finally里再合适不过了

文章目录

说说你的ES7-ES12的了解

ES2016(ES7)

ES2017(ES8)

ES2018(ES9)

说说你的ES7-ES12的了解

ES2016(ES7)

Array.prototype.includes()

includes() 方法用来判断一个数组是否包含一个指定的值,如果包含则返回 true,否则返回 false。


语法

arr.includes(valueToFind[, fromIndex])

valueToFind,需要查找的元素值。

fromIndex 可选 从fromIndex 索引处开始查找 valueToFind。如果为负值(即从末尾开始往前跳 fromIndex 的绝对值个索引,然后往后搜寻)。默认为 0。


使用 includes()只能判断简单类型的数据,对于复杂类型的数据,比如对象类型的数组,二维数组,这些是无法判断的.

如果只想知道某个值是否在数组中存在,而并不关心它的索引位置,建议使用includes(),如果想获取一个值在数组中的位置,那么使用indexOf方法。


幂运算符

console.log(2 ** 10); // 1024

幂运算符的两个*号之间不能出现空格,否则语法会报错。


ES2017(ES8)

Object.values()

Object.values 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。


const obj = {

 name: "jimmy",

 age: 18,

 height: 188,

};

console.log(Object.values(obj));

// [ 'jimmy', 18, 188 ]

1

2

3

4

5

6

7

Object.entries()

Object.entries() 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的键值对数组。


const obj = {

 name: "jimmy",

 age: 18,

 height: 188,

};

console.log(Object.entries(obj));

// [ [ 'name', 'jimmy' ], [ 'age', 18 ], [ 'height', 188 ] ]

console.log(Object.entries([1, 2, 3]));

// [ [ '0', 1 ], [ '1', 2 ], [ '2', 3 ] ]

1

2

3

4

5

6

7

8

9

Object.getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptors() 方法用来获取一个对象的所有自身属性的描述符。


const obj = {

 name: "jimmy",

 age: 18,

};

const desc = Object.getOwnPropertyDescriptors(obj);

console.log(desc);  

// 打印结果

{

 name: {

   value: 'jimmy',

   writable: true,

   enumerable: true,

   configurable: true

 },

 age: {

  value: 18,

  writable: true,

  enumerable: true,

  configurable: true

 }

}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

●value表示当前对象的默认值

●writable表示对象属性是否可以修改

●enumerable表示当前这个属性是否可以出现在对象的枚举属性中

●configurable表示当前对象的属性能否用delete删除


设置 writable: false和configurable: false,为false时,对象的name对象的值不能改变和不能被删除,打印出来还是原来的对象。


String.prototype.padStart

把指定字符串填充到字符串头部,返回新字符串。

语法

str.padStart(targetLength [, padString])


targetLength

当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。

padString 可选

填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断。此参数的默认值为 " "


应用场景

日期格式化:yyyy-mm-dd的格式:


const now = new Date()

const year = now.getFullYear()

// 月份和日期 如果是一位前面给它填充一个0

const month = (now.getMonth() + 1).toString().padStart(2, '0')

const day = (now.getDate()).toString().padStart(2, '0')

console.log(year, month, day)

console.log( `${year}-${month}-${day}` )

//输入今天的日期

1

2

3

4

5

6

7

8

数字替换(手机号,银行卡号等)


const tel = '18781268679'

const newTel = tel.slice(-4).padStart(tel.length, '*')

console.log(newTel) // *******5678

1

2

3

String.prototype.padEnd

把指定字符串填充到字符串尾部,返回新字符串。


应用场景

在JS前端我们处理时间戳的时候单位是ms毫秒,但是,后端同学返回的时间戳则不一样是毫秒,可能只有10位,以s秒为单位。所以,我们在前端处理这个时间戳的时候,保险起见,要先做一个13位的补全,保证单位是毫秒


尾逗号 Trailing commas

ES8 允许函数的最后一个参数有尾逗号(Trailing comma)。 此前,函数定义和调用时,都不允许最后一个参数后面出现逗号。


async/await

使用 Promise 能很好地解决回调地狱的问题,但如果处理流程比较复杂的话,那么整段代码将充斥着 then,语义化不明显,代码不能很好地表示执行流程

async/await是比 Promise 更优雅的异步方式

前面添加了async的函数在执行后都会自动返回一个Promise对象:


function foo() {

   return 'jimmy'

}

console.log(foo()) // 'jimmy'

1

2

3

4

添加async后


async function foo() {

   return 'jimmy' // Promise.resolve('jimmy')

}

console.log(foo()) // Promise

foo()

1

2

3

4

5

async函数中使用await,那么await这里的代码就会变成同步的了,意思就是说只有等await后面的Promise执行完成得到结果才会继续下去,await就是等待。


function timeout() {

   return new Promise(resolve => {

       setTimeout(() => {

           console.log(1)

           resolve()

       }, 1000)

   })

}


// 不加async和await是2、1   加了是1、2

async function foo() {

   await timeout()

   console.log(2)

}

foo()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

使用场景

假如有这样一个使用场景:需要先请求 a 链接,等返回信息之后,再请求 b 链接的另外一个资源。下面代码展示的是使用 fetch 来实现这样的需求,fetch 被定义在 window 对象中,它返回的是一个 Promise 对象


fetch('https://blog.csdn.net/')

 .then(response => {

   console.log(response)

   return fetch('https://juejin.im/')

 })

 .then(response => {

   console.log(response)

 })

 .catch(error => {

   console.log(error)

 })

1

2

3

4

5

6

7

8

9

10

11

虽然上述代码可以实现这个需求,但语义化不明显,代码不能很好地表示执行流程。基于这个原因,ES8 引入了 async/await,这是 JavaScript 异步编程的一个重大改进,提供了在不阻塞主线程的情况下使用同步代码实现异步访问资源的能力,并且使得代码逻辑更加清晰。

通过上面代码,你会发现整个异步处理的逻辑都是使用同步代码的方式来实现的,而且还支持 try catch 来捕获异常,这感觉就在写同步代码,所以是非常符合人的线性思维的。


注意点

●await 只能在 async 标记的函数内部使用,单独使用会触发 Syntax error。

●await后面需要跟异步操作,不然就没有意义,而且await后面的Promise对象不必写then,因为await的作用之一就是获取后面Promise对象成功状态传递出来的参数。


async/await的缺陷

Async/await 让你的代码看起来是同步的,在某种程度上,也使得它的行为更加地同步。 await 关键字会阻塞其后的代码,直到promise完成,就像执行同步操作一样。它确实可以允许其他任务在此期间继续运行,但您自己的代码被阻塞

这意味着您的代码可能会因为大量await的promises相继发生而变慢。每个await都会等待前一个完成,而你实际想要的是所有的这些promises同时开始处理(就像我们没有使用async/await时那样)。


ES2018(ES9)

Object Rest & Spread

在 ES9 新增 Object 的 Rest & Spread 方法


const input = {

 a: 1,

 b: 2,

 c: 3,

}


const output = {

 ...input,

 c: 4

}


console.log(output)

// {a: 1, b: 2, c: 4}

1

2

3

4

5

6

7

8

9

10

11

12

13

这块代码展示了 spread 语法,可以把 input 对象的数据都拓展到 output 对象,这个功能很实用。需要注意的是,如果存在相同的属性名,只有最后一个会生效

注意点


const obj = { x: { y: 10 } };

const copy1 = { ...obj };

const copy2 = { ...obj };

obj.x.y = "jimmy";

console.log(copy1, copy2);

// x: {y: "jimmy"} x: {y: "jimmy"}

console.log(copy1.x === copy2.x);

// → true

1

2

3

4

5

6

7

8

如果属性的值是一个对象的话,该对象的引用会被拷贝,而不是生成一个新的对象。


const input = {

 a: 1,

 b: 2,

 c: 3

}


let { a, ...rest } = input


console.log(a, rest) // 1 {b: 2, c: 3}

1

2

3

4

5

6

7

8

9

当对象 key-value 不确定的时候,把必选的 key 赋值给变量,用一个变量收敛其他可选的 key 数据,这在之前是做不到的。注意,rest 属性必须始终出现在对象的末尾,否则将抛出错误


for await of

异步迭代器(for-await-of):循环等待每个Promise对象变为resolved状态才进入下一步。

ES9 中可以用 for…await…of 的语法来操作


function TimeOut(time) {

   return new Promise(function(resolve, reject) {

       setTimeout(function() {

           resolve(time)

       }, time)

   })

}


async function test() {

   let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)]

   for await (let item of arr) {

       console.log(Date.now(), item)

   }

}

test()

// 1560092345730 2000

// 1560092345730 1000

// 1560092346336 3000


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

for await of 环等待每个Promise对象变为resolved状态才进入下一步。所有打印的结果为 2000,1000,3000


Promise.prototype.finally()

Promise.prototype.finally() 方法返回一个Promise,在promise执行结束时,无论结果是fulfilled或者是rejected,在执行then()和catch()后,都会执行finally指定的回调函数。这为指定执行完promise后,无论结果是fulfilled还是rejected都需要执行的代码提供了一种方式,避免同样的语句需要在then()和catch()中各写一次的情况。


使用场景

loading关闭

需要每次发送请求,都会有loading提示,请求发送完毕,就需要关闭loading提示框,不然界面就无法被点击。不管请求成功或是失败,这个loading都需要关闭掉,这时把关闭loading的代码写在finally里再合适不过了


目录
相关文章
|
18天前
|
前端开发 JavaScript 网络协议
前端最常见的JS面试题大全
【4月更文挑战第3天】前端最常见的JS面试题大全
40 5
|
3月前
|
存储 前端开发 JavaScript
十个超级有用的JavaScript的高阶面试技巧!
十个超级有用的JavaScript的高阶面试技巧!
|
7天前
|
JavaScript 前端开发 测试技术
「一劳永逸」送你21道高频JavaScript手写面试题(上)
「一劳永逸」送你21道高频JavaScript手写面试题
33 0
|
1月前
|
设计模式 JavaScript 前端开发
最常见的26个JavaScript面试题和答案
最常见的26个JavaScript面试题和答案
44 1
|
1月前
|
存储 JavaScript 前端开发
【JavaScript】面试手撕浅拷贝
引入 浅拷贝和深拷贝应该是面试时非常常见的问题了,为了能将这两者说清楚,于是打算用两篇文章分别解释下深浅拷贝。 PS: 我第一次听到拷贝这个词,有种莫名的熟悉感,感觉跟某个英文很相似,后来发现确实Copy的音译,感觉这翻译还是蛮有意思的
45 6
|
1月前
|
JavaScript 前端开发
【JavaScript】面试手撕节流
上篇我们讲了防抖,这篇我们就谈谈防抖的好兄弟 -- 节流。这里在老生常谈般的提一下他们两者之间的区别,顺带给读者巩固下。
53 3
|
2月前
|
前端开发 JavaScript UED
【JavaScript】面试手撕防抖
防抖: 首先它是常见的性能优化技术,主要用于处理频繁触发的浏览器事件,如窗口大小变化、滚动事件、输入框内容改变等。在用户连续快速地触发同一事件时,防抖机制会确保相关回调函数在一个时间间隔内只会被执行一次。
36 0
|
2月前
|
前端开发 JavaScript 算法
【JavaScript】面试手撕数组排序
这章主要讲的是数组的排序篇,我们知道面试的时候,数组的排序是经常出现的题目。所以这块还是有必要进行一下讲解的。笔者观察了下前端这块的常用算法排序题,大概可以分为如下
24 2
|
2月前
|
JavaScript 前端开发 索引
【JavaScript】面试手撕数组原型链(易)
续借上文,这篇文章主要讲的是数组原型链相关的考题,有些人可能会纳闷,数组和原型链之间有什么关系呢?我们日常使用的数组forEach,map等都是建立在原型链之上的。举个🌰,如我有一个数组const arr = [1,2,3]我想要调用arr.sum方法对arr数组的值进行求和,该如何做呢?我们知道数组没有sum函数,于是我们需要在数组的原型上定义这个函数,才能方便我们调用,具体代码如下。接下来我们就是采用这种方式去实现一些数组常用的方法。
39 6
|
2月前
|
JavaScript 前端开发
【JavaScript】面试手写题精讲之数组(上)
该专题主要是讲解我们在面试的时候碰到一些JS的手写题, 确实这种手写题还是比较恶心的。有些时候好不容易把题目写出来了,突然面试官冷不丁来一句有没有更优的解法,直接让我们僵在原地。为了解决兄弟们的这些困扰,这个专题于是就诞生啦。我们会将一些常见的不是最优解的答案作为对比,方便大家更好理解。
38 3