前置涩话
掘金的小伙伴们大家好,这里是家里蹲选手sin~ 今天是第六天了,马上就要坚持一周了。也是小小得进行了一波简历海投,不出所料,通通遁入虚空,听不到一丝回响 o(╥﹏╥)o 但是没关系,还有好多知识没有学到呢,先坚持完这一周把!加油ヾ(◍°∇°◍)ノ゙
✅ 常见的函数方法手写实现
call、apply及bind
区别:
三者的第一个参数都是this需要指向的对象,但在后续的参数上只有apply是接收一个数组,call和bind的参数用逗号分开。
call和apply直接调用,返回的是一个值,而bind不直接调用,返回的是一个函数形式,执行:foo.bind(obj)()
实现call
Function.prototype.myCall = function(ctx, ...args) {
ctx = ctx === undefined || ctx === null ? globalThis : Object(ctx); // ctx一定是对象
const fn = this; // 待执行的函数
// 用symbol作为属性名
const key = Symbol('temp');
// ctx[key] = fn
Object.defineProperty(ctx, key, {
enumerable: false,
value: fn
});
const result = ctx[key](...args);
delete ctx[key];
return result;
};
第一个参数指定的this打印是包装类型如[string:'a'],所以使用Object()包装(参数归一化,把参数归一成对象一种情况)
ctx里没有fn(),所以不能ctx.fn()。让函数调用this指向ctx,所以用ctx调用,给ctx新加一个不可枚举的symbol属性,值为执行函数
实现bind
Function.prototype.myBind = function(ctx) {
//var args = Array.prototype.slice.call(argument, 1);
let args = [...arguments].slice(1); // 将arguments变成数组并且去掉第一个参数
let fn = this;
return function A() {
// 返回的函数调用时可能会有参数
let restArgs = [...arguments];
let allArgs = args.concat(restArgs);
// 需要判断新函数是否用new调用,new调用实际是new了返回的函数,所以使用原型进行判断
if (Object.getPrototypeOf(this) === A.prototype) {
return new fn(...allArgs); // es6使用new调用
//下面方法需要完善(手写new实现)
//var obj = {};
//Object.setPrototypeOf(obj, fn.prototype);
//fn.apply(obj, allArgs);
//return obj;
} else {
return fn.apply(ctx, allArgs);
};
};
};
高阶函数
使用函数作为另一个函数的参数
封装动画函数、函数防抖、并发队列、参数归一化、惰性函数、分时函数封装、函数柯里化
柯里化函数:固定某一个函数的参数,得到函数剩余参数的新函数,如果没有剩余参数则调用。
函数防抖(回城)
- 频繁调用某一个函数
- 造成效率问题
- 结果以最后一次为准
function debounce(func, duration = 500) {
let timerId;
return function(...args) {
clearTimeout(timerId);
timerId = setTimeout(() => {
func.apply(this, args);
},duration);
};
};
函数节流(技能CD)
- 频繁调用某一个函数
- 造成效率问题
- 设定时间内只出一次结果
function throttle(callback, time, immediately = true) {
if (immediately) { //立即执行一次
let t
return function() {
if (!t || Date.now() - t >= time) {
callback.apply(null, arguments)
t = Date.now
}
}
} else {
let timer
return function(...args) {
if (timer) return
timer = setTimeout(() => {
callback.apply(this, args)
timer = null
}, time)
}
}
}
并发队列
function paralleTask(tasks, paralleCount = 2) {
return new Promise((resolve) => {
if (tasks.length === 0) {
resolve();
return
}
let nextIndex = 0;
let finishCount = 0;
function _run() {
//运行下一个任务
const task = tasks[nextIndex];
nextIndex++;
task().then(() => {
finishCount++;
if (nextIndex <tasks.length) {
_run();
} else if (finishCount === tasks.length) {
resolve();
};
});
};
for (let i = 0; i < paralleCount && i <= tasks.length; i++) {
_run();
};
});
};
封装分时函数
const chunkSplitor = (task) => {
setTimeout(() => {
task((time) => time < 16);
}, 30);
};
function performChunk(datas, consumer, chunkSplitor) {
if (typeof datas === 'number') {
datas = new Array(datas);
}
if (datas.length === 0) {
return
};
if (!chunkSplitor && globalThis.requestIdleCallback) {
chunkSplitor = (task) => {
requestIdleCallback((idle) => {
task(() => idle.timeRemaining());
});
};
};
let i = 0; //目前应该取出的任务下标
//执行一块任务
function _run() {
if (i === datas.length) {
return
};
chunkSplitor((hasTime) => {
const now = Date.now();
while (hasTime(Date.now() - now) && i < datas.length) {
//在这一帧还有空闲时间
const item = datas[i];
consumer(item, i);
i++;
};
_run();
});
};
_run();
};
封装动画函数
function animation(duration, from, to, onProgress) {
const dis = to - from;
const speed = dis / duration;
const startTime = Date.now();
let value = from;
onProgress(value);
function _run() {
const now = Date.now();
const time = now - startTime;
if (time >= duration) {
value = to;
onProgress(value);
return
}
const d = time * speed;
value = from + d;
onProgress(value);
requestAnimationFrame(_run);
};
requestAnimationFrame(_run);
};
统计函数 array.filter(fn).length
function countBy(array, generateKey) {
const result = {};
for (const u of array) {
const key = generateKey(u);
if (result[key]) {
result[key]++;
} else {
result[key] = 1;
};
};
return result;
};
数据分组
function groupBy(arr, generateKey) {
if (typeof generateKey === 'string') {
const propName = generateKey;
generateKey = (item) => item[propName];
};
const result = {};
for (const item of arr) {
const key = generateKey(item);
if (!result[key]) {
result[key] = [];
};
result[key].push(item);
};
return result;
};
深度克隆
function deepclone(value) {
const cache = new WeakMap();
function _deepclone(value) {
if (value === null || typeof value !== 'object') {
return value;
};
if (cache.has(value)) {
return cache.get(value);
};
const result = Array.isArray(value) ? [] : {};
Object.setPrototypeOf(result, Object.getPrototypeOf(value));
cache.set(value, result);
for (const key in value) {
if (value.hasOwnProperty(key)) {
result[key] = _deepclone(value[key]);
};
};
return result;
};
return _deepclone(value);
};
柯里化函数
function curry(func) {
//得到从下标1开始的参数
let args = Array.prototype.slice.call(arguments, 1);
let that = this;
return function() {
let curArgs = Array.from(arguments); //当前调用的参数
let totalArgs = args.concat(curArgs);
if (totalArgs.length >= func.length) {
//参数数量够
return func.apply(null, totalArgs);
} else {
//参数数量不够
totalArgs.unshift(func);
return that.curry.apply(that, totalArgs);
};
};
};
惰性函数
function createCopyText() {
if (navigator.clipboard) {
return (text) => {
navigator.clipboard.writeText(text);
};
} else {
return (text) => {
const input = document.createElement('input');
input.setAttribute('value', text);
document.body.appendChild(input);
input.select();
document.execCommand('copy');
document.body.removeChild(input);
};
};
};
const copyText = createCopyText();
实现Promise
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
#state = PENDING
#result = undefined
#handlers = []
constructor(executor) {
const resolve = (data) => {
this.#changeState(FULFILLED, data)
}
const reject = (reason) => {
this.#changeState(REJECTED, reason)
}
try{
executor(resolve, reject)
}
catch(err) {
reject(err)
} //无法捕获异步错误
}
#changeState(state, result) {
if(this.#state !== PENDING) return
this.#state = state
this.#result = result
this.#run()
}
#isPromise(value) {
return (
value !== null &&
(typeof value === 'object' || typeof value === 'function') &&
typeof value.then === 'function'
)
}
#runMicroTask(func) {
// node环境
// process.nextTick(func)
if (typeof process !== 'underfined' && typeof process.nextTick === 'function') {
return process.nextTick(func)
} else if (typeof MutationObserver === 'function') {
// 浏览器环境
// MutationObserver
const ob = new MutationObserver(func)
const textNode = document.createTextNode()
ob.observe(textNode, {
characterData: true
})
textNode.data = '2'
} else {
setTimeout(func, 0)
}
}
#runOne(callback, resolve, reject) {
//this.#runMicroTask(() => {
if (typeof callback !== 'function') {
const settled = this.#state === FULFILLED ? resolve : reject
settled(this.#result)
return
}
try {
const data = callback(this.#result)
if (this.#isPromise(data)) {
data.then(resolve, reject)
} else {
resolve(data)
}
} catch (err) {
reject(err)
}
//})
}
#run() {
if (this.#state === PENDING) return
while (this.#handles.length) {
const { onFulfilled, onRejected, resolve, reject } = this.#handlers.shift()
if (this.#state === FULFILLED) {
this.#runOne(onFulfilled, resolve, reject)
} else {
this.#runOne(onRejected, resolve, reject)
}
}
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this.#handlers.push({
onFulfilled,
onRejected,
resolve,
reject
})
this.#run()
})
}
}
Promise.myAll = function(proms){
let res, rej
const p = new Promise((resolve, reject)=>{
res = resolve
rej = reject
})
let i = 0
let fulfilled = 0
const result = []
for (let prom of proms) {
const index = i
i++
Promise.resolve(prom).then((data)=>{
//1.把完成的数据汇总到最终结果
result[index] = data
//2.判定是否全部完成
fulfilled++
if (fulfilled === i) {
res(result)
}
}, rej)
}
if (i === 0) {
res([])
}
return p;
}
片尾涩话
<{=....(嘎嘎嘎~) 今天这部分可烧脑了,你们学会了吗 反正我是学废了︿( ̄︶ ̄)︿