前端应该要掌握的几种手写代码实现

  • 使用 call / apply 指定 this

  • 返回一个绑定函数

  • 当返回的绑定函数作为构造函数被new调用,绑定的上下文指向实例对象

  • 设置绑定函数的prototype 为原函数的prototype

Function.prototype.myBind = function(context, …args) {

const fn = this

const bindFn = function (…newFnArgs) {

fn.call(

this instanceof bindFn ? this : context,

…args, …newFnArgs

)

}

bindFn.prototype = Object.create(fn.prototype)

return bindFn

}

模拟new
  • 创建一个新的空对象

  • this绑定到空对象

  • 使空对象的__proto__指向构造函数的原型(prototype)

  • 执行构造函数,为空对象添加属性

  • 判断构造函数的返回值是否为对象,如果是对象,就使用构造函数的返回值,否则返回创建的对象

const createNew = (Con, …args) => {

const obj = {}

Object.setPrototypeOf(obj, Con.prototype)

let result = Con.apply(obj, args)

return result instanceof Object ? result : obj

}

模拟instanceOf
  • 遍历左边变量的原型链,直到找到右边变量的 prototype,如果没有找到,返回 false

const myInstanceOf = (left, right) => {

let leftValue = left.proto

let rightValue = right.prototype

while(true) {

if(leftValue === null) return false

if(leftValue === rightValue) return true

leftValue = leftValue.proto

}

}

深拷贝(简单版)
  • 判断类型是否为原始类型,如果是,无需拷贝,直接返回

  • 为避免出现循环引用,拷贝对象时先判断存储空间中是否存在当前对象,如果有就直接返回

  • 开辟一个存储空间,来存储当前对象和拷贝对象的对应关系

  • 对引用类型递归拷贝直到属性为原始类型

const deepClone = (target, cache = new WeakMap()) => {

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

return target

}

if(cache.get(target)) {

return target

}

const copy = Array.isArray(target) ? [] : {}

cache.set(target, copy)

Object.keys(target).forEach(key => copy[key] = deepClone(obj[key], cache))

return copy

}

深拷贝(尤雨溪版)

vuex源码

  • 原理与上一版类似

function find(list, f) {

return list.filter(f)[0]

}

function deepCopy(obj, cache = []) {

// just return if obj is immutable value

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

return obj

}

// if obj is hit, it is in circular structure

const hit = find(cache, c => c.original === obj)

if (hit) {

return hit.copy

}

const copy = Array.isArray(obj) ? [] : {}

// put the copy into cache at first

// because we want to refer it in recursive deepCopy

cache.push({

original: obj,

copy

})

Object.keys(obj).forEach(key => copy[key] = deepCopy(obj[key], cache))

return copy

}

函数防抖
  • this继承自父级上下文,指向触发事件的目标元素

  • 事件被触发时,传入event对象

  • 传入leading参数,判断是否可以立即执行回调函数,不必要等到事件停止触发后才开始执行

  • 回调函数可以有返回值,需要返回执行结果

const debounce = (fn, wait = 300, leading = true) => {

let timerId, result

return function(…args) {

timerId && clearTimeout(timerId)

if (leading) {

if (!timerId) result = fn.apply(this, args)

timerId = setTimeout(() => timerId = null, wait)

} else {

timerId = setTimeout(() => result = fn.apply(this, args), wait)

}

return result

}

}

函数节流(定时器)

const throttle = (fn, wait = 300) => {

let timerId

return function(…args) {

if(!timerId) {

timerId = setTimeout(() => {

timerId = null

return result = fn.apply(this, …args)

}, wait)

}

}

}

函数节流(时间戳)

const throttle = (fn, wait = 300) => {

let prev = 0

let result

return function(…args) {

let now = +new Date()

if(now - prev > wait) {

prev = now

return result = fn.apply(this, …args)

}

}

}

函数节流实现方法区别

| 方法 | 使用时间戳 | 使用定时器 |

| — | — | — |

| 开始触发时 | 立刻执行 | n秒后执行 |

| 停止触发后 | 不再执行事件 | 继续执行一次事件 |

数组去重

const uniqBy = (arr, key) => {

return […new Map(arr.map(item) => [item[key], item])).values()]

}

const singers = [

{ id: 1, name: ‘Leslie Cheung’ },

{ id: 1, name: ‘Leslie Cheung’ },

{ id: 2, name: ‘Eason Chan’ },

]

console.log(uniqBy(singers, ‘id’))

// [

// { id: 1, name: ‘Leslie Cheung’ },

// { id: 2, name: ‘Eason Chan’ },

// ]

原理是利用Map的键不可重复

数组扁平化(技巧版)

const flatten = (arr) => arr.toString().split(‘,’).map(item => +item)

数组扁平化

const flatten = (arr, deep = 1) => {

return arr.reduce((cur, next) => {

return Array.isArray(next) && deep > 1 ?

[…cur, …flatten(next, deep - 1)] :

[…cur, next]

},[])

}

函数柯里化

const currying = (fn) {

_curry = (…args) =>

args.length >= fn.length

? fn(…args)
(…newArgs) => _curry(…args, …newArgs)

}

原理是利用闭包把传入参数保存起来,当传入参数的数量足够执行函数时,就开始执行函数

发布订阅EventEmitter

最后

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

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

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

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

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

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

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

[外链图片转存中…(img-vAiD4rjK-1715885133026)]

[外链图片转存中…(img-Xfm7QZMO-1715885133026)]

[外链图片转存中…(img-y9RBqc9c-1715885133026)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值