面试阿里运营一般问什么,一份精心总结的3万字ES6实用指南(下,金三银四前端面试的一些感受

本文详细介绍了ES6的关键特性如浅克隆、字符串处理方法、异步编程(包括Async函数和Promise.prototype.finally)、正则表达式的具名组匹配等。同时探讨了微信小程序的文件类型、数据请求封装、性能优化以及与原生App的比较。此外,还涉及了Webpack的工作原理和面试中可能被问到的技术问题,如防抖、节流和二叉树遍历等。
摘要由CSDN通过智能技术生成

//{

//  name: { configurable: true, enumerable: true, value: “布兰”, writable: true },

//  age: {configurable: false, enumerable: false, value: 12, writable: false}

//}

配合 Object.create() 可以实现浅克隆:

const shallowClone = (obj) => Object.create(

Object.getPrototypeOf(obj),

Object.getOwnPropertyDescriptors(obj)

)

String.prototype.padStart()

str.padStart(length [, padStr]) 会返回一个新字符串,该字符串将从 str 字符串的左侧开始填充某个字符串 padStr(非必填,如果不是字符串则会转成字符串, 传入 undefined 和不传这个参数效果一致)直到达到指定位数 length 为止:

‘abc’.padStart(5, 2)          // ‘22abc’

‘abc’.padStart(5, undefined)  // ’  abc’

‘abc’.padStart(5, {})         // ‘[oabc’

‘abc’.padStart(5)             // ’  abc’

‘abcde’.padStart(2, ‘f’)      // ‘abcde’

String.prototype.padEnd()

规则和 padStart 类似,但是是从字符串右侧开始填充:

‘abc’.padEnd(5, 2)  // ‘abc22’

函数参数尾逗号

允许函数在定义和调用的时候时候最后一个参数后加上逗号:

function init(

param1,

param2,

) { }

init(‘a’, ‘b’,)

Async函数

  • 使用 async 可以声明一个 async 函数,结合 await 可以用一种很简介的方法写成基于 Promise 的异步行为,而不需要刻意的链式调用。await 表达式会暂停整个 async 函数的执行进程并出让其控制权,只有当其等待的基于 Promise 的异步操作被兑现或被拒绝之后才会恢复进程。async 函数有如下几种定义形式:

// 函数声明

async function foo() {}

// 函数表达式

let foo = async function() {}

// 箭头函数

let foo = async () => {}

// 对象方法

lef obj = {

async foo() {}

}

// 类方法

class Dog {

async bark() {}

}

  • async 函数一定会返回一个 Promise 对象,所以它可以使用 then 添加处理函数。如果一个 async 函数的返回值看起来不是Promise,那么它将会被隐式地包装在一个 Promise 中:

async function foo() {

return ‘a’

}

foo().then(res => {

console.log(res)  // ‘a’

})

  • 内部如果发生错误,或者显示抛出错误,那么 async 函数会返回一个 rejected 状态的 Promsie

async function foo() {

throw new Error(‘error’)

}

foo().catch(err => {

console.log(err)  // Error: error

})

  • 返回的 Promise 对象必须等到内部所有 await 命令 Promise 对象执行完才会发生状态改变,除非遇到 return 语句或抛出错误;任何一个 await 命令返回的 Promise 对象变 为rejected 状态,整个 Async 函数都会中断后续执行:

async function fn() {

let a = await Promise.resolve(‘success’)

console.log(‘a_’ + a)

let b = await Promise.reject(‘fail’)

console.log(‘b_’ + b)  // 不会执行

}

fn().then(res => {

console.log(res)  // 不会执行

}, err => {

console.log(err)

})

// ‘a_success’

// ‘fail’

  • 所以为了保证  async 里的异步操作都能完成,我们需要将他们放到 try...catch() 块里或者在 await 返回的 Promise 后跟一个 catch 处理函数:

async function fn() {

try {

let a = await Promise.reject(‘a fail’)

console.log(‘a_’ + a)  // 不会执行

} catch (e) {

console.log(e)  // ‘a fail’

}

let b = await Promise.reject(‘b fail’)

.catch(e => {

console.log(e)  // ‘b fail’

})

console.log(‘b_’ + b)  // ‘bundefined’

}

fn().then(res => {

console.log(res)  // undefined

}, err => {

console.log(err)  // 不会执行

})

  • 如果 async 函数里的多个异步操作之间没有依赖关系,建议将他们写到一起减少执行时间:

// 写法一

let [foo, bar] = await Promise.all([getFoo(), getBar()])

// 写法二

let fooPromise = getFoo()

let barPromise = getBar()

let foo = await fooPromise

let bar = await barPromise

  • await 命令只能用在 async 函数之中,如果用在普通函数,就会报错。

共享内存和Atomics对象

  • SharedArrayBuffer

  • Atomics

ES2018


Promise.prototype.finally()

Promise.prototype.finally() 用于给 Promise 对象添加 onFinally 函数,这个函数主要是做一些清理的工作,只有状态变化的时候才会执行该 onFinally 函数。

function onFinally() {

console.log(888)  // 并不会执行

}

new Promise((resolve, reject) => {

}).finally(onFinally)

finally() 会生成一个 Promise 新实例,finally 一般会原样后传父 Promise,无论父级实例是什么状态:

let p1 = new Promise(() => {})

let p2 = p1.finally(() => {})

setTimeout(console.log, 0, p2)  // Promise {}

let p3 = new Promise((resolve, reject) => {

resolve(3)

})

let p4 = p3.finally(() => {})

setTimeout(console.log, 0, p3)  // Promise {: 3}

上面说的是一般,但是也有特殊情况,比如 finally 里返回了一个非 fulfilledPromise 或者抛出了异常的时候,则会返回对应状态的新实例:

let p1 = new Promise((resolve, reject) => {

resolve(3)

})

let p2 = p1.finally(() => new Promise(() => {}))

setTimeout(console.log, 0, p2)  // Promise {}

let p3 = p1.finally(() => Promise.reject(6))

setTimeout(console.log, 0, p3)  // Promise {: 6}

let p4 = p1.finally(() => {

throw new Error(‘error’)

})

setTimeout(console.log, 0, p4)  // Promise {: Error: error}

参考:

  • 深入理解Promise

异步迭代器

想要了解异步迭代器最好的方式就是和同步迭代器进行对比。我们知道可迭代数据的内部都是有一个 Symbol.iterator 属性,它是一个函数,执行后会返回一个迭代器对象,这个迭代器对象有一个 next() 方法可以对数据进行迭代,next() 执行后会返回一个对象,包含了当前迭代值 value 和 标识是否完成迭代的 done 属性:

let iterator = [1, 2]Symbol.iterator

iterator.next()  // { value: 1, done: false }

iterator.next()  // { value: 2, done: false }

iterator.next()  // { value: undefinde, done: true }

上面这里的 next() 执行的是同步操作,所以这个是同步迭代器,但是如果 next() 里需要执行异步操作,那就需要异步迭代了,可异步迭代数据的内部有一个 Symbol.asyncIterator 属性,基于此我们来实现一个异步迭代器:

class Emitter {

constructor(iterable) {

this.data = iterable

}

Symbol.asyncIterator {

let length = this.data.length,

index = 0;

return {

next:() => {

const done = index >= length

const value = !done ? this.data[index++] : undefined

return new Promise((resolve, reject) => {

resolve({value, done})

})

}

}

}

}

异步迭代器的 next() 会进行异步的操作,通常是返回一个 Promise,所以需要对应的处理函数去处理结果:

let emitter = new Emitter([1, 2, 3])

let asyncIterator = emitterSymbol.asyncIterator

asyncIterator.next().then(res => {

console.log(res)  // { value: 1, done: false }

})

asyncIterator.next().then(res => {

console.log(res)  // { value: 2, done: false }

})

asyncIterator.next().then(res => {

console.log(res)  // { value: 3, done: false }

})

另外也可以使用 for await...of 来迭代异步可迭代数据:

let asyncIterable = new Emitter([1, 2, 3])

async function asyncCount() {

for await (const x of asyncIterable ) {

console.log(x)

}

}

asyncCount()

// 1 2 3

另外还可以通过异步生成器来创建异步迭代器:

class Emitter {

constructor(iterable) {

this.data = iterable

}

async *Symbol.asyncIterator {

let length = this.data.length,

index = 0;

while (index < length) {

yield this.data[index++]

}

}

}

async function asyncCount() {

let emitter = new Emitter([1, 2, 3])

const asyncIterable = emitterSymbol.asyncIterator

for await (const x of asyncIterable ) {

console.log(x)

}

}

asyncCount()

// 1 2 3

参考:

  • Iteration_protocols

  • for-await…of

s修饰符(dotAll模式)

正则表达式新增了一个 s 修饰符,使得 . 可以匹配任意单个字符:

/foo.bar/.test(‘foo\nbar’)   // false

/foo.bar/s.test(‘foo\nbar’)  // true

上面这又被称为 dotAll 模式,表示点(dot)代表一切字符。所以,正则表达式还引入了一个dotAll属性,返回一个布尔值,表示该正则表达式是否处在dotAll模式:

/foo.bar/s.dotAll  // true

具名组匹配

正则表达式可以使用捕获组来匹配字符串,但是想要获取某个组的结果只能通过对应的索引来获取:

let re = /(\d{4})-(\d{2})-(\d{2})/

let result = re.exec(‘2015-01-02’)

// result[0] === ‘2015-01-02’

// result[1] === ‘2015’

// result[2] === ‘01’

// result[3] === ‘02’

而现在我们可以通过给捕获组 (?<name>...) 加上名字 name ,通过名字来获取对应组的结果:

let re = /(?\d{4})-(?\d{2})-(?\d{2})/

let result = re.exec(‘2015-01-02’)

// result.groups.year === ‘2015’

// result.groups.month === ‘01’

// result.groups.day === ‘02’

配合解构赋值可以写出非常精简的代码:

let {groups: {year, month, day}} = /(?\d{4})-(?\d{2})-(?\d{2})/.exec(‘2015-01-02’)

console.log(year, month, day)  // 2015 01 02

具名组也可以通过传递给 String.prototype.replace 的替换值中进行引用。如果该值为字符串,则可以使用 $<name> 获取到对应组的结果:

let re = /(?\d{4})-(?\d{2})-(?\d{2})/

let result = ‘2015-01-02’.replace(re, ‘ < d a y > / <day>/ <day>//$’)

// result === ‘02/01/2015’

参考:

  • proposal-regexp-named-groups

后行断言

后行断言:(?<=y)xx 只有在 y 后面才能匹配:

/(?<=$)\d+/.exec(‘I have $100.’)  // [‘100’]

后行否定断言:(?<!y)xx 只有不在 y 后面才能匹配:

/(?<!$)\d+/.exec(‘I have $100.’)  // [‘00’]

Unicode属性转义

允许正则表达式匹配符合 Unicode 某种属性的所有字符,\p{...} 是匹配包含,\P{...} 是匹配不包含的字符,且必须搭配 /u 修饰符才会生效:

/\p{Emoji}+/u.exec(‘???笑死我了???不行了’)  // [‘???’]

/\P{Emoji}+/u.exec(‘???笑死我了???不行了’)  // [‘笑死我了’]

这里可以查询到更多的 Unicode 的属性 Full_Properties

对象扩展运算符

对象的扩展运算符可以用到解构赋值上,且只能应用到最后一个变量上:

let {x, …y} = {x: 1, a: 2, b: 3}

console.log(y)  // {a: 2, b: 3}

对象扩展运算符不能解构原型上的属性:

let obj = { x: 1 }

obj.proto = { y: 2 }

let {…a} = obj

console.log(a.y)  // undefined

应用一:可以实现浅拷贝,但是不会拷贝原始属性:

let person = Object.create({ name: ‘布兰’ })

person.age = 12

// 浅拷贝写法一

let { …pClone1 } = person

console.log(pClone1)  // { age: 12 }

console.log(pClone1.name)  // undefined

// 浅拷贝写法二

let pClone2 = {…person}

console.log(pClone2)  // { age: 12 }

console.log(pClone2.name)  // undefined

应用二:合并两个对象:

let ab = {…a, …b}

// 等同于

let ab = Object.assign({}, a, b);

应用三:重写对象属性

let aWithOverrides = { …a, x: 1, y: 2 };

应用四:给新对象设置默认值

let aWithDefaults = { x: 1, y: 2, …a };

应用五:利用扩展运算符的解构赋值可以扩展函数参数:

function baseFunction({ a, b }) {}

function wrapperFunction({ x, y, …restConfig }) {

// 使用 x 和 y 参数进行操作

// 其余参数传给原始函数

return baseFunction(restConfig)

}

参考:

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

ES6

  • 列举常用的ES6特性:

  • 箭头函数需要注意哪些地方?

  • let、const、var

  • 拓展:var方式定义的变量有什么样的bug?

  • Set数据结构

  • 拓展:数组去重的方法

  • 箭头函数this的指向。

  • 手写ES6 class继承。

微信小程序

  • 简单描述一下微信小程序的相关文件类型?

  • 你是怎么封装微信小程序的数据请求?

  • 有哪些参数传值的方法?

  • 你使用过哪些方法,来提高微信小程序的应用速度?

  • 小程序和原生App哪个好?

  • 简述微信小程序原理?

  • 分析微信小程序的优劣势

  • 怎么解决小程序的异步请求问题?

其他知识点面试

  • webpack的原理

  • webpack的loader和plugin的区别?

  • 怎么使用webpack对项目进行优化?

  • 防抖、节流

  • 浏览器的缓存机制

  • 描述一下二叉树, 并说明二叉树的几种遍历方式?

  • 项目类问题

  • 笔试编程题:

最后

技术栈比较搭,基本用过的东西都是一模一样的。快手终面喜欢问智力题,校招也是终面问智力题,大家要准备一下一些经典智力题。如果排列组合、概率论这些基础忘了,建议回去补一下。

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

ES6 class继承。

微信小程序

  • 简单描述一下微信小程序的相关文件类型?

  • 你是怎么封装微信小程序的数据请求?

  • 有哪些参数传值的方法?

  • 你使用过哪些方法,来提高微信小程序的应用速度?

  • 小程序和原生App哪个好?

  • 简述微信小程序原理?

  • 分析微信小程序的优劣势

  • 怎么解决小程序的异步请求问题?

其他知识点面试

  • webpack的原理

  • webpack的loader和plugin的区别?

  • 怎么使用webpack对项目进行优化?

  • 防抖、节流

  • 浏览器的缓存机制

  • 描述一下二叉树, 并说明二叉树的几种遍历方式?

  • 项目类问题

  • 笔试编程题:

最后

技术栈比较搭,基本用过的东西都是一模一样的。快手终面喜欢问智力题,校招也是终面问智力题,大家要准备一下一些经典智力题。如果排列组合、概率论这些基础忘了,建议回去补一下。

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

  • 28
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值