手撕js,不说一句话搞定一场面试

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’

}

*/

let queryString = ‘’

Object.keys(params).forEach(key => {

queryString += ${key}=${params[key]}&

})

if (queryString) { // id=1&xxx=abc&

// 去除最后的&

queryString = queryString.substring(0, queryString.length-1)

// 接到url

url += ‘?’ + queryString

}

// 1. 执行异步ajax请求

// 创建xhr对象

const request = new XMLHttpRequest()

// 打开连接(初始化请求, 没有请求)

request.open(method, url, true)

// 发送请求

if (method===‘GET’) {

request.send()

} else if (method===‘POST’ || method===‘PUT’ || method===‘DELETE’){

request.setRequestHeader(‘Content-Type’, ‘application/json;charset=utf-8’) // 告诉服务器请求体的格式是json

request.send(JSON.stringify(data)) // 发送json格式请求体参数

}

// 绑定状态改变的监听

request.onreadystatechange = function () {

// 如果请求没有完成, 直接结束

if (request.readyState!==4) {

return

}

// 如果响应状态码在[200, 300)之间代表成功, 否则失败

const {status, statusText} = request

// 2.1. 如果请求成功了, 调用resolve()

if (status>=200 && status<=299) {

// 准备结果数据对象response

const response = {

data: JSON.parse(request.response),

status,

statusText

}

resolve(response)

} else { // 2.2. 如果请求失败了, 调用reject()

reject(new Error('request error status is ’ + status))

}

}

})

}

/* 发送特定请求的静态方法 */

axios.get = function (url, options) {

return axios(Object.assign(options, {url, method: ‘GET’}))

}

axios.delete = function (url, options) {

return axios(Object.assign(options, {url, method: ‘DELETE’}))

}

axios.post = function (url, data, options) {

return axios(Object.assign(options, {url, data, method: ‘POST’}))

}

axios.put = function (url, data, options) {

return axios(Object.assign(options, {url, data, method: ‘PUT’}))

}

export default axios

12. 自定义事件总线

/*

  • 自定义事件总线

*/

const eventBus = {}

/*

{

add: [callback1, callback2]

delete: [callback3]

}

*/

let callbacksObj = {}

/*

绑定事件监听

*/

eventBus.on = function (eventName, callback) {

const callbacks = callbacksObj[eventName]

if (callbacks) {

callbacks.push(callback)

} else {

callbacksObj[eventName] = [callback]

}

}

/*

分发事件

*/

eventBus.emit = function (eventName, data) {

const callbacks = callbacksObj[eventName]

if (callbacks && callbacks.length > 0) {

callbacks.forEach(callback => {

callback(data)

})

}

}

/*

移除事件监听

*/

eventBus.off = function (eventName) {

if (eventName) {

delete callbacksObj[eventName]

} else {

callbacksObj = {}

}

}

export default eventBus

13.自定义new工具函数

/*

自定义new工具函数

语法: newInstance(Fn, …args)

功能: 创建Fn构造函数的实例对象

实现: 创建空对象obj, 调用Fn指定this为obj, 返回obj

*/

export function newInstance(Fn, …args) {

// 创建一个新的对象

const obj = {}

// 执行构造函数

const result = Fn.apply(obj, args) // 相当于: obj.Fn()

// 如果构造函数执行的结果是对象, 返回这个对象

if (result instanceof Object) {

return result

}

// 如果不是, 返回新创建的对象

obj.proto.constructor = Fn // 让原型对象的构造器属性指向Fn

return obj

}

14. 如何在 JS 中“深冻结”对象

如果咱们想要确保对象被深冻结,就必须创建一个递归函数来冻结对象类型的每个属性:

1. 没有深冻结

let person = {

name: “Leonardo”,

profession: {

name: “developer”

}

};

Object.freeze(person);

person.profession.name = “doctor”;

console.log(person); //output { name: ‘Leonardo’, profession: { name: ‘doctor’ } }

2. 深冻结

function deepFreeze(object) {

let propNames = Object.getOwnPropertyNames(object);

for (let name of propNames) {

let value = object[name];

object[name] = value && typeof value === “object” ? deepFreeze(value) : value;

}

return Object.freeze(object);

}

let person = {

name: “Leonardo”,

profession: {

name: “developer”

}

};

deepFreeze(person);

person.profession.name = “doctor”; // TypeError: Cannot assign to read only property

15. 自定义数组声明式系列方法

1. map()方法实现

/*

实现数组声明式处理系列工具函数

*/

/*

实现map()

*/

export function map (array, callback) {

const arr = []

for (let index = 0; index < array.length; index++) {

arr.push(callback(array[index], index))

}

return arr

}

2. 实现reduce()

/*

实现reduce()

*/

export function reduce (array, callback, initValue) {

let result = initValue

for (let index = 0; index < array.length; index++) {

// 调用回调函数将返回的结果赋值给result

result = callback(result, array[index], index)

}

return result

}

3.实现filter()

/*

实现filter()

*/

export function filter(array, callback) {

const arr = []

for (let index = 0; index < array.length; index++) {

if (callback(array[index], index)) {

arr.push(array[index])

}

}

return arr

}

/*

4.实现find()

/*

实现find()

*/

export function find (array, callback) {

for (let index = 0; index < array.length; index++) {

if (callback(array[index], index)) {

return array[index]

}

}

return undefined

}

5.实现findIndex()

/*

实现findIndex()

*/

export function findIndex (array, callback) {

for (let index = 0; index < array.length; index++) {

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

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

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

img

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

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

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

基础知识是前端一面必问的,如果你在基础知识这一块翻车了,就算你框架玩的再6,webpack、git、node学习的再好也无济于事,因为对方就不会再给你展示的机会,千万不要因为基础错过了自己心怡的公司。前端的基础知识杂且多,并不是理解就ok了,有些是真的要去记。当然了我们是牛x的前端工程师,每天像背英语单词一样去背知识点就没必要了,只要平时工作中多注意总结,面试前端刷下题目就可以了。

什么?你问面试题资料在哪里,这不是就在你眼前吗(滑稽

callback) {

for (let index = 0; index < array.length; index++) {

if (callback(array[index], index)) {

return array[index]

}

}

return undefined

}

5.实现findIndex()

/*

实现findIndex()

*/

export function findIndex (array, callback) {

for (let index = 0; index < array.length; index++) {

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

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

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

[外链图片转存中…(img-swEp0kgy-1713838191902)]

[外链图片转存中…(img-rM7bwHel-1713838191902)]

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

[外链图片转存中…(img-rzk7o77a-1713838191903)]

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

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

[外链图片转存中…(img-v3ihdotK-1713838191903)]

最后

基础知识是前端一面必问的,如果你在基础知识这一块翻车了,就算你框架玩的再6,webpack、git、node学习的再好也无济于事,因为对方就不会再给你展示的机会,千万不要因为基础错过了自己心怡的公司。前端的基础知识杂且多,并不是理解就ok了,有些是真的要去记。当然了我们是牛x的前端工程师,每天像背英语单词一样去背知识点就没必要了,只要平时工作中多注意总结,面试前端刷下题目就可以了。

什么?你问面试题资料在哪里,这不是就在你眼前吗(滑稽

资料领取方式:戳这里免费领取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值