手撕js,不说一句话搞定一场面试(1),银行软件开发面试题

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

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

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

如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
img

正文

self.callbacks.forEach(cbsObj => {

cbsObj.onResolved(value)

})

})

}

}

/*

将promise的状态改为失败, 指定失败的reason

*/

function reject(reason) {

// 如果当前不是pending, 直接结束

if (self.status !== PENDING) return

self.status = REJECTED // 将状态改为失败

self.data = reason // 保存reason数据

// 异步调用所有缓存的待执行失败的回调函数

if (self.callbacks.length > 0) {

// 启动一个延迟时间为0的定时器, 在定时器的回调中执行所有失败的回调

setTimeout(() => {

self.callbacks.forEach(cbsObj => {

cbsObj.onRejected(reason)

})

})

}

}

// 调用excutor来启动异步任务

try {

excutor(resolve, reject)

} catch (error) { // 执行器执行出错, 当前promise变为失败

console.log(‘-----’)

reject(error)

}

}

/*

用来指定成功/失败回调函数的方法

1). 如果当前promise是resolved, 异步执行成功的回调函数onResolved

2). 如果当前promise是rejected, 异步执行成功的回调函数onRejected

3). 如果当前promise是pending, 保存回调函数

返回一个新的promise对象

它的结果状态由onResolved或者onRejected执行的结果决定

2.1). 抛出error ==> 变为rejected, 结果值为error

2.2). 返回值不是promise ==> 变为resolved, 结果值为返回值

2.3). 返回值是promise ===> 由这个promise的决定新的promise的结果(成功/失败)

*/

Promise.prototype.then = function (onResolved, onRejected) {

const self = this

onResolved = typeof onResolved === ‘function’ ? onResolved : value => value // 将value向下传递

onRejected = typeof onRejected === ‘function’ ? onRejected : reason => {

throw reason

} // 将reason向下传递

return new Promise((resolve, reject) => { // 什么时候改变它的状态

/*

  1. 调用指定的回调函数

  2. 根据回调执行结果来更新返回promise的状态

*/

function handle(callback) {

try {

const result = callback(self.data)

if (!(result instanceof Promise)) { // 2.2). 返回值不是promise ==> 变为resolved, 结果值为返回值

resolve(result)

} else { // 2.3). 返回值是promise ===> 由这个promise的决定新的promise的结果(成功/失败)

result.then(

value => resolve(value),

reason => reject(reason)

)

// result.then(resolve, reject)

}

} catch (error) { // 2.1). 抛出error ==> 变为rejected, 结果值为error

reject(error)

}

}

if (self.status === RESOLVED) {

setTimeout(() => {

handle(onResolved)

})

} else if (self.status === REJECTED) {

setTimeout(() => {

handle(onRejected)

})

} else { // PENDING

self.callbacks.push({

onResolved(value) {

handle(onResolved)

},

onRejected(reason) {

handle(onRejected)

}

})

}

})

}

/*

用来指定失败回调函数的方法

catch是then的语法糖

*/

Promise.prototype.catch = function (onRejected) {

return this.then(undefined, onRejected)

}

/*

用来返回一个指定vlaue的成功的promise

value可能是一个一般的值, 也可能是promise对象

*/

Promise.resolve = function (value) {

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

// 如果value是一个promise, 最终返回的promise的结果由value决定

if (value instanceof Promise) {

value.then(resolve, reject)

} else { // value不是promise, 返回的是成功的promise, 成功的值就是value

resolve(value)

}

})

}

/*

用来返回一个指定reason的失败的promise

*/

Promise.reject = function (reason) {

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

reject(reason)

})

}

/*

返回一个promise, 只有当数组中所有promise都成功才成功, 否则失败

*/

Promise.all = function (promises) {

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

let resolvedCount = 0 // 已经成功的数量

const values = new Array(promises.length) // 用来保存成功promise的value值

// 遍历所有promise, 取其对应的结果

promises.forEach((p, index) => {

p.then(

value => {

resolvedCount++

values[index] = value

if (resolvedCount === promises.length) { // 都成功了

resolve(values)

}

},

reason => reject(reason)

)

})

})

}

/*

返回一个promise, 由第一个完成promise决定

*/

Promise.race = function (promises) {

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

// 遍历所有promise, 取其对应的结果

promises.forEach(p => {

// 返回的promise由第一个完成p来决定其结果

p.then(resolve, reject)

})

})

}

/*

返回一个延迟指定时间才成功(也可能失败)的promise

*/

Promise.resolveDelay = function (value, time) {

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

setTimeout(() => {

// 如果value是一个promise, 最终返回的promise的结果由value决定

if (value instanceof Promise) {

value.then(resolve, reject)

} else { // value不是promise, 返回的是成功的promise, 成功的值就是value

resolve(value)

}

}, time)

})

}

/*

返回一个延迟指定时间才失败的promise

*/

Promise.rejectDelay = function (reason, time) {

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

setTimeout(() => {

reject(reason)

}, time)

})

}

export default Promise

2. 手写一个深拷贝函数

/**

  • 深拷贝

*/

const obj1 = {

age: 20,

name: ‘xxx’,

address: {

city: ‘beijing’

},

arr: [‘a’, ‘b’, ‘c’]

}

const obj2 = deepClone(obj1)

obj2.address.city = ‘shanghai’

obj2.arr[0] = ‘a1’

console.log(obj1.address.city)

console.log(obj1.arr[0])

/**

  • 深拷贝

  • @param {Object} obj 要拷贝的对象

*/

function deepClone(obj = {}) {

if (typeof obj !== ‘object’ || obj == null) {

// obj 是 null ,或者不是对象和数组,直接返回

return obj

}

// 初始化返回结果

let result

if (obj instanceof Array) {

result = []

} else {

result = {}

}

for (let key in obj) {

// 保证 key 不是原型的属性

if (obj.hasOwnProperty(key)) {

// 递归调用!!!

result[key] = deepClone(obj[key])

}

}

// 返回结果

return result

}

3. 手写一个防抖函数

export function debounce(callback, delay) {

return function () {

// console.log(‘debounce 事件…’)

// 保存this和arguments

const that = this

const args = arguments

// 清除待执行的定时器任务

if (callback.timeoutId) {

clearTimeout(callback.timeoutId)

}

// 每隔delay的时间, 启动一个新的延迟定时器, 去准备调用callback

callback.timeoutId = setTimeout(function () {

callback.apply(that, args)

// 如果定时器回调执行了, 删除标记

delete callback.timeoutId

}, delay)

}

}

4. 手写一个节流函数

/*

实现函数节流的函数

*/

export function throttle(callback, delay) {

let start = 0 // 必须保存第一次点击立即调用

return function () {

// 它的this是谁就得让callback()中的this是谁, 它接收的所有实参都直接交给callback()

console.log(‘throttle 事件’)

const current = Date.now()

if (current - start > delay) { // 从第2次点击开始, 需要间隔时间超过delay

callback.apply(this, arguments)

start = current

}

}

}

5. 手写bind()

import {call} from ‘./call’

/*

自定义函数对象的bind方法

重要技术:

高阶函数

闭包

call()

三点运算符

*/

export function bind (fn, obj, …args) {

if (obj=null || obj=undefined) {

obj = obj || window

}

return function (…args2) {

call(fn, obj, …args, …args2)

}

}

6. 手写call()

/*

自定义函数对象的call方法

*/

export function call (fn, obj, …args) {

// 如果传入的是null/undefined, this指定为window

if (obj=null || obj=undefined) {

obj = obj || window

}

// 给obj添加一个方法: 属性名任意, 属性值必须当前调用call的函数对象

obj.tempFn = fn

// 通过obj调用这个方法

const result = obj.tempFn(…args)

// 删除新添加的方法

delete obj.tempFn

// 返回函数调用的结果

return result

}

7. 手写apply()

/*

自定义函数对象的apply方法

*/

export function apply (fn, obj, args) {

// 如果传入的是null/undefined, this指定为window

if (obj=null || obj=undefined) {

obj = obj || window

}

// 给obj添加一个方法: 属性名任意, 属性值必须当前调用call的函数对象

obj.tempFn = fn

// 通过obj调用这个方法

const result = obj.tempFn(…args)

// 删除新添加的方法

delete obj.tempFn

// 返回函数调用的结果

return result

}

8. 手写bind()

import {call} from ‘./call’

/*

自定义函数对象的bind方法

重要技术:

高阶函数

闭包

call()

三点运算符

*/

export function bind (fn, obj, …args) {

if (obj=null || obj=undefined) {

obj = obj || window

}

return function (…args2) {

call(fn, obj, …args, …args2)

}

}

9. 数组扁平化

/*

数组扁平化: 取出嵌套数组(多维)中的所有元素放到一个新数组(一维)中

如: [1, [3, [2, 4]]] ==> [1, 3, 2, 4]

*/

/*

方法一: 递归 + reduce() + concat()

*/

export function flatten1 (array) {

return array.reduce((pre, item) => {

if (Array.isArray(item)) {

return pre.concat(flatten1(item))

} else {

return pre.concat(item)

}

}, [])

}

/*

方法二: … + some() + concat()

*/

export function flatten2 (array) {

let arr = [].concat(…array)

while (arr.some(item => Array.isArray(item))) {

arr = [].concat(…arr)

}

return arr

}

10. 自定义消息订阅与发布

/*

自定义消息订阅与发布

*/

const PubSub = {}

/*

{

add: {

token1: callback1,

token2: callback2

},

update: {

token3: callback3

}

}

*/

let callbacksObj = {} // 保存所有回调的容器

let id = 0 // 用于生成token的标记

// 1. 订阅消息

PubSub.subscribe = function (msgName, callback) {

// 确定token

const token = ‘token_’ + ++id

// 取出当前消息对应的callbacks

const callbacks = callbacksObj[msgName]

if (!callbacks) {

callbacksObj[msgName] = {

}

} else {

callbackstoken = callback

}

// 返回token

return token

}

// 2. 发布异步的消息

PubSub.publish = function (msgName, data) {

// 取出当前消息对应的callbacks

let callbacks = callbacksObj[msgName]

// 如果有值

if (callbacks) {

// callbacks = Object.assign({}, callbacks)

// 启动定时器, 异步执行所有的回调函数

setTimeout(() => {

Object.values(callbacks).forEach(callback => {

callback(data)

})

}, 0)

}

}

// 3. 发布同步的消息

PubSub.publishSync = function (msgName, data) {

// 取出当前消息对应的callbacks

const callbacks = callbacksObj[msgName]

// 如果有值

if (callbacks) {

// 立即同步执行所有的回调函数

Object.values(callbacks).forEach(callback => {

callback(data)

})

}

}

/*

  1. 取消消息订阅

1). 没有传值, flag为undefined

2). 传入token字符串

3). msgName字符串

*/

PubSub.unsubscribe = function (flag) {

// 如果flag没有指定或者为null, 取消所有

if (flag === undefined) {

callbacksObj = {}

} else if (typeof flag === ‘string’) {

if (flag.indexOf(‘token_’) === 0) { // flag是token

// 找到flag对应的callbacks

const callbacks = Object.values(callbacksObj).find(callbacks => callbacks.hasOwnProperty(flag))

// 如果存在, 删除对应的属性

if (callbacks) {

delete callbacks[flag]

}

} else { // flag是msgName

delete callbacksObj[flag]

}

} else {

throw new Error(‘如果传入参数, 必须是字符串类型’)

}

}

export default PubSub

11. 手写axios函数

/*

  1. 函数的返回值为promise, 成功的结果为response, 失败的结果为error

  2. 能处理多种类型的请求: GET/POST/PUT/DELETE

  3. 函数的参数为一个配置对象

{

url: ‘’, // 请求地址

method: ‘’, // 请求方式GET/POST/PUT/DELETE

params: {}, // GET/DELETE请求的query参数

data: {}, // POST或DELETE请求的请求体参数

}

  1. 响应json数据自动解析为js的对象/数组

*/

/* 发送任意类型请求的函数 */

function axios({

url,

method=‘GET’,

params={},

data={}

}) {

// 返回一个promise对象

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

// 处理method(转大写)

method = method.toUpperCase()

// 处理query参数(拼接到url上) id=1&xxx=abc

/*

{

id: 1,

xxx: ‘abc’

}

结尾

学习html5、css、javascript这些基础知识,学习的渠道很多,就不多说了,例如,一些其他的优秀博客。但是本人觉得看书也很必要,可以节省很多时间,常见的javascript的书,例如:javascript的高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。

html5

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

/*

  1. 函数的返回值为promise, 成功的结果为response, 失败的结果为error

  2. 能处理多种类型的请求: GET/POST/PUT/DELETE

  3. 函数的参数为一个配置对象

{

url: ‘’, // 请求地址

method: ‘’, // 请求方式GET/POST/PUT/DELETE

params: {}, // GET/DELETE请求的query参数

data: {}, // POST或DELETE请求的请求体参数

}

  1. 响应json数据自动解析为js的对象/数组

*/

/* 发送任意类型请求的函数 */

function axios({

url,

method=‘GET’,

params={},

data={}

}) {

// 返回一个promise对象

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

// 处理method(转大写)

method = method.toUpperCase()

// 处理query参数(拼接到url上) id=1&xxx=abc

/*

{

id: 1,

xxx: ‘abc’

}

结尾

学习html5、css、javascript这些基础知识,学习的渠道很多,就不多说了,例如,一些其他的优秀博客。但是本人觉得看书也很必要,可以节省很多时间,常见的javascript的书,例如:javascript的高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。

[外链图片转存中…(img-DmNTMaO8-1713086217599)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-ga523Ti7-1713086217600)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值