1. 防抖
function debounce(func, ms = 1000) {
let timer; return function (...args) {
if (timer) {
clearTimeout(timer) } timer = setTimeout(() => {
(this, args)
}, ms) }}// 测试
const task = () => { console.log('run task') }
const debounceTask = debounce(task, 1000)
window.addEventListener('scroll', debounceTask)
复制代码
2. 节流
function throttle(func, ms = 1000) {
let canRun = true
return function (...args) {
if (!canRun) return
canRun = false
setTimeout(() => {
(this, args)
canRun = true
}, ms) }}// 测试
const task = () => { console.log('run task') }
const throttleTask = throttle(task, 1000)
window.addEventListener('scroll', throttleTask)
复制代码
我自己是一名从事了多年开发的web前端老程序员,目前辞职在做自己的web前端私人定制课程,今年我花了一个月整理了一份最适合2020年学习的web前端学习干货,各种框架都有整理,送给每一位前端小伙伴,想要获取的可以添加我的web前端交流群【572512676】,即可免费获取。
3. new
functionmyNew(Func, ...args) {
const instance = {}; if () {
(instance, ) } const res = (instance, args) if (typeof res === "function" || (typeof res === "object" && res !== null)) {
return res
} return instance
}// 测试functionPerson(name) {
= name}Person.prototype.sayName = function() {
console.log(`My name is ${}`)
}const me = myNew(Person, 'Jack')
()console.log(me)
复制代码
4. bind
Function.prototype.myBind = function (context = globalThis) {
const fn = this
const args = Array.from(arguments).slice(1)
const newFunc = function () {
const newArgs = (...arguments)
if (thisinstanceof newFunc) {
5. call
Function.prototype.myCall = function (context = globalThis) {
// 关键步骤,在 context 上调用方法,触发 this 绑定为 context,使用 Symbol 防止原有属性的覆盖 const key = Symbol('key') context[key] = this
// es5 可通过 for 遍历 arguments 得到参数数组 const args = [...arguments].slice(1)
const res = context[key](...args)
delete context[key] return res};// 测试const me = { name: 'Jack' }function say() { (`My name is ${ || 'default'}`);
}(me)复制代码
6. apply
Function.prototype.myApply = function (context = globalThis) {
// 关键步骤,在 context 上调用方法,触发 this 绑定为 context,使用 Symbol 防止原有属性的覆盖 const key = Symbol('key') context[key] = this
let res if (arguments[1]) {
res = context[key](...arguments[1])
} else { res = context[key]()
} delete context[key] return res}// 测试const me = { name: 'Jack' }function say() { (`My name is ${ || 'default'}`);
}(me)复制代码
7. deepCopy
function deepCopy(obj, cache = new WeakMap()) {
if (!obj instanceof Object) return obj
// 防止循环引用
if ((obj)) return (obj)
// 支持函数
if (obj instanceof Function) {
return function () {
return obj.apply(this, arguments)
} } // 支持日期
if (obj instanceof Date) returnnew Date(obj)
// 支持正则对象
if (obj instanceof RegExp) returnnew RegExp(obj.source, obj.flags)
// 还可以增加其他对象,比如:Map, Set等,根据情况判断增加即可,面试点到为止就可以了
// 数组是 key 为数字素银的特殊对象
const res = (obj) ? [] : {} // 缓存 copy 的对象,用于处理循环引用的情况
(obj, res) (obj).forEach((key) => {
if (obj[key] instanceof Object) {
res[key] = deepCopy(obj[key], cache) } else {
res[key] = obj[key] } }); return res
}// 测试
const source = { name: 'Jack',
meta: { age: 12,
birth: new Date('1997-10-10'),
ary: [1, 2, { a: 1 }],
say() { console.log('Hello');
} }}source.source = sourceconst newObj = deepCopy(source)console.log([2] === [2]); // false
(newObj.meta.birth === source.meta.birth); //false
复制代码
8. 事件总线 | 发布订阅模式
classEventEmitter{
constructor() {
this.cache = {}
} on(name, fn) { if (this.cache[name]) {
this.cache[name].push(fn)
} else {
this.cache[name] = [fn]
} } off(name, fn) { const tasks = this.cache[name]
if (tasks) {
const index = ((f) => f === fn || f.callback === fn)
if (index >= 0) {
(index, 1)
} } } emit(name) { if (this.cache[name]) {
9. 柯里化:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数
functioncurry(func) {
returnfunctioncurried(...args) {
// 关键知识点:function.length 用来获取函数的形参个数
// 补充: 获取的是实参个数
if(args.length >= func.length) {
return (this, args)
} returnfunction(...args2) {
return curried.apply(this, args.concat(args2))
} }}// 测试functionsum(a, b, c) {
return a + b + c
}const curriedSum = curry(sum)console.log(curriedSum(1, 2, 3))
console.log(curriedSum(1)(2,3))
console.log(curriedSum(1)(2)(3))
复制代码
10. es5 实现继承
functioncreate(proto) {
functionF() {}
F.prototype = proto; return new F();
}// Parentfunction Parent(name) { = name}.sayName = function() {
console.log()
};// Childfunction Child(age, name) { (this, name) = age}Child.prototype = create()
Child.prototype.constructor = ChildChild.prototype.sayAge = function() {
console.log()
}// 测试const child = new Child(18, 'Jack')
()()复制代码
11. instanceof
functionisInstanceOf(instance, klass) {
let proto = instance.__proto__
let prototype = klass.prototype
while (true) {
if (proto === null) returnfalse
if (proto === prototype) returntrue
proto = }}
12. 异步并发数限制
functionlimit(count, array, iterateFunc) {
const tasks = []
const doingTasks = []
let i = 0
const enqueue = () => {
if (i === ) {
returnPromise.resolve()
} const task = Promise.resolve().then(() => iterateFunc(array[i++]))
(task) const doing = (() => ((doing), 1))
(doing) const res = doingTasks.length >= count ? Promise.race(doingTasks) : Promise.resolve()
return (enqueue)
}; return enqueue().then(() =>Promise.all(tasks))
}
13. 异步串行 | 异步并行
// 字节面试题,实现一个异步加法
function asyncAdd(a, b, callback) { setTimeout(function () { callback(null, a + b);
}, 500);
}// 解决方案
//1. promisify
const promiseAdd = (a, b) =>new Promise((resolve, reject) => {
asyncAdd(a, b, (err, res) => {
if (err) {
reject(err) } else {
resolve(res) } })})//2. 串行处理
async function serialSum(...args) { return args.reduce((task, now) => task.then(res => promiseAdd(res, now)), (0))
}//3. 并行处理
async function parallelSum(...args) { if (args.length === 1) return args[0]
const tasks = [] for (let i = 0; i < args.length; i += 2) {
(promiseAdd(args[i], args[i + 1] || 0))
} const results = await (tasks)
return parallelSum(...results)
}// 测试
(async () => { console.log('Running...');
const res1 = await serialSum(1, 2, 3, 4, 5, 8, 9, 10, 11, 12)
console.log(res1)
const res2 = await parallelSum(1, 2, 3, 4, 5, 8, 9, 10, 11, 12)
console.log(res2)
console.log('Done');
})()复制代码
14. vue reactive
// Dep module
class Dep { static stack = [] static target = null
deps = null
constructor() { this.deps = new Set()
} depend() { if () {
this.deps.add()
} } notify() { this.deps.forEach(w => ())
} static pushTarget(t) { if (this.target) {
this.stack.push(this.target)
} this.target = t
} static popTarget() { this.target = this.stack.pop()
}}// reactive
function reactive(o) { if (o && typeof o === 'object') {
(o).forEach(k => { defineReactive(o, k, o[k]) }) } return o
}function defineReactive(obj, k, val) { let dep = new Dep()
(obj, k, { get() { () return val
}, set(newVal) { val = newVal () } }) if (val && typeof val === 'object') {
reactive(val) }}// watcher
class Watcher { constructor(effect) { this.effect = effect
this.update()
} update() { (this)
this.value = this.effect()
() returnthis.value
}}// 测试代码
const data = reactive({ msg: 'aaa'
})new Watcher(() => {
console.log('===> effect', );
})setTimeout(() => {
= 'hello'
}, 1000)
复制代码
15. promise
// 建议阅读 [Promises/A+ 标准]()
class MyPromise { constructor(func) { this.status = 'pending'
this.value = null this.resolvedTasks = [] this.rejectedTasks = [] this._resolve = this._resolve.bind(this) = .bind(this) try { func(this._resolve, ) } catch (error) {
(error)
} } _resolve(value) { setTimeout(() => { this.status = 'fulfilled'
this.value = value (t => t(value)) }) } _reject(reason) { setTimeout(() => { this.status = 'reject'
this.value = reason (t => t(reason)) }) } then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
((value) => { try { const res = onFulfilled(value) if (res instanceof MyPromise) {
res.then(resolve, reject)
} else {
resolve(res) } } catch (error) {
reject(error)
} }) ((value) => { try { const res = onRejected(value) if (res instanceof MyPromise) {
res.then(resolve, reject)
} else {
reject(res) } } catch (error) {
reject(error)
} }) }) } catch(onRejected) { return this.then(null, onRejected);
}}// 测试new MyPromise((resolve) => { setTimeout(() => { resolve(1);
}, 500);
}).then((res) => {
console.log(res);
return new MyPromise((resolve) => {
setTimeout(() => { resolve(2);
}, 500);
}); }).then((res) => {
console.log(res);
throw new Error('a error')
}).catch((err) => { console.log('==>', err);
})复制代码
16. 数组扁平化
// 方案 1
function recursionFlat(ary = []) { const res = [] (item => { if ((item)) {
(...recursionFlat(item)) } else {
(item) } }) return res
}// 方案 2
function reduceFlat(ary = []) { return ary.reduce((res, item) => ((item) ? reduceFlat(item) : item), [])
}// 测试
const source = [1, 2, [3, 4, [5, 6]], '7']
console.log(recursionFlat(source))
console.log(reduceFlat(source))
复制代码
17. 对象扁平化
functionobjectFlat(obj = {}) {
const res = {}
functionflat(item, preKey = '') {
Object.entries(item).forEach(([key, val]) => {
const newKey = preKey ? `${preKey}.${key}` : key
if (val && typeof val === 'object') {
flat(val, newKey) } else {
res[newKey] = val } }) } flat(obj) return res
}
18. 图片懒加载
// <img src="" data-src="https://xxxx/">
functionisVisible(el) {
const position = () const windowHeight = // 顶部边缘可见 const topVisible = position.top > 0 && position.top < windowHeight;
// 底部边缘可见 const bottomVisible = position.bottom < windowHeight && position.bottom > 0;
return topVisible || bottomVisible;
}functionimageLazyLoad() {
const images = ('img')
for (let img of images) {
const realSrc = if (!realSrc) continue
if (isVisible(img)) {
img.src = realSrc = ''
} }}// 测试('load', imageLazyLoad)
('scroll', imageLazyLoad)
// or('scroll', throttle(imageLazyLoad, 1000))