new
new 关键字做了什么事
- 创建一个新的对象
- 将构造函数的原型链赋值到新的对象中
- 构造函数中是否返回引用类型的值不是则返回创建的对象
实现
javascript
function myNew(ctx, ...arg) {
// 1.创建新对象
let obj = {};
// 2. 将构造函数的原型链赋值到新的对象中
obj.__proto__ = ctx.prototype;
// 3构造函数中是否返回引用类型的值不是则返回创建的对象
let result = ctx.apply(obj, arg);
return typeof result === "object" ? result : obj;
}
bind
核心
- 返回一个新函数原型链不会被修改
- 新函数的
this
关键字绑定到参数的context
上,且如果没传默认为window
- 函数参数可以在
bind
时绑定,也可以在新函数中绑定 - 当新函数当做构造函数时(new)
this
指向新函数。
实现
js
Array.prototype.bind = function (context, ...args) {
const fn = this;
function tmp(...arg) {
return fn.apply(this instanceof tmp ? this : context, [...args, ...arg]);
}
tmp.prototype = fn.prototype;
return tmp;
};
Object.create
核心
方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型
实现
js
Object.prototype.create = function (proto) {
function fn() {}
fn.prototype = proto;
fn.constructor = fn;
return new fn();
};
instanceof
核心
用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
实现
js
function myInstanceof(left, right) {
let leftPrototype = Object.getPrototypeOf(left);
let rightPrototype = right.prototype;
while (leftPrototype) {
if (leftPrototype === rightPrototype) {
return true;
}
leftPrototype = Object.getPrototypeOf(leftPrototype);
}
return false;
}
深克隆
注意点
这次只实现 dom 节点、循环引用、时间、正则、Map、对象、函数、Set,Symbol 的克隆
实现
js
function isComplex(data) {
return data && typeof data !== "object" && typeof data !== "symbol";
}
const constructors = [RegExp, Date, Set, Map, WeakMap, WeakSet];
function deepClone(obj, hash = new WeakMap()) {
if (hash.has(obj)) return hash.get(obj);
if (constructors.includes(obj.constructor)) {
return new obj.constructor(obj);
}
if (obj instanceof HTMLElement) {
return obj.cloneNode(true);
}
if (typeof obj === "symbol") {
return Symbol(obj.description);
}
if (typeof obj === "function") {
return new Function(`return ${obj.toString()}`)();
}
const desc = Object.getOwnPropertyDescriptors(obj);
const copy_obj = Object.create(Object.getPrototypeOf(obj), desc);
for (let key in obj) {
copy_obj[key] = isComplex(obj[key]) ? deepClone(obj[key], hash) : obj[key];
}
return copy_obj;
}
并发限制
核心
利用调度以及开关控制并发数量
实现
es6
js
function p_limit(limit, tasks, callback) {
const p_tasks = tasks.slice();
let counter = 0;
let running = 0;
let called = 0;
const result = [];
function run() {
if (p_tasks.length && counter <= limit) {
const task = p_tasks.shift();
running++;
task()
.then((res) => {
result[called++] = res;
if (called === counter) {
callback(result);
}
})
.finally(() => {
running--;
run();
});
run();
}
}
function push(task) {
p_tasks.push(task);
counter++;
}
return { run, push };
}
const timeout = (i) => () =>
new Promise((resolve) => {
console.log("正在执行i", i);
setTimeout(() => {
console.log("准备执行完成i", i);
resolve(i);
}, i * 1000);
});
const { run, push } = limitRequest(
4,
[
timeout(4),
timeout(1),
timeout(7),
timeout(2),
timeout(3),
timeout(8),
timeout(5),
timeout(9),
timeout(6),
timeout(7),
],
(res) => {
console.log("result", res);
}
);
run();
push(timeout(11));
ES7 版本
Details
js
function p_limit(limit, tasks, callback) {
const p_tasks = tasks.slice();
let counter = p_tasks.length;
const ret = [];
const executing = [];
async function run() {
for (const task of p_tasks) {
const p = Promise.resolve().then(() => task());
ret.push(p);
if (limit <= counter) {
const e = p.then(() => executing.splice(executing.indexOf(e), 1));
executing.push(e);
if (executing.length >= limit) {
await Promise.race(executing);
}
}
}
await Promise.all(ret);
callback(ret);
}
function push(task) {
p_tasks.push(task);
counter++;
}
return { run, push };
}
洋葱模型
核心
使用 next 来执行下一个函数,可以衍生到 async/await
的自动调用 next
Co
实现
js
function compose(middleware) {
if (!Array.isArray(middleware)) return;
for (let fn of middleware) {
if (typeof fn !== "function") {
return;
}
}
return (context, next) => {
let index = -1;
return dispatch(0);
function dispatch(i) {
if (i >= middleware.length) return;
index = i;
const fn = middleware[i];
if (i === middleware.length) {
fn = next;
}
if (!fn) return Promise.resolve();
try {
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
} catch (e) {
return Promise.reject(e);
}
}
};
}
防抖
实现
js
function debounce(fn, time, opt={ immediate = false }) {
let timer = null;
return function () {
if (timer) clearTimeout(timer);
if (opt.immediate) {
let called = !timer;
if (called) {
timer = setTimeout(function () {
timer = null;
}, wait);
} else {
fn.apply(null);
}
} else {
timer = setTimeout(() => {
fn.apply(null);
}, time);
}
};
}
节流
实现
js
function throttle(fn, time, opt = { immediate: false }) {
let timer = null;
let startTime = Date.now();
return function () {
const diff = time - (Date.now() - startTime);
clearTimeout(timer);
if (diff > 0) {
timer = setTimeout(() => {
fn.apply(null);
startTime = Date.now();
}, diff);
} else {
fn.apply(null);
startTime = Date.now();
}
};
}
Promise
all
js
const isFunction = (it) => typeof it === "function";
Promise.prototype.all = function (promises) {
return new Promise((resolve, reject) => {
let result = [];
let done = 0;
for (let i = 0; i < promises.length; i++) {
const task = promises[i];
if (isFunction(task)) {
Promise.resolve()
.then(() => task())
.then((res) => {
result[i] = res;
done++;
if (done === promises.length) {
resolve(result);
}
})
.catch(reject);
}
}
});
};
并发限制
- 普通版
js
function sendRequest(urls, max, callback) {
let i = 0;
const ret = [];
let finned = 0;
function request(index) {
if (finned === urls.length) {
callback(ret);
return;
}
if (index >= urls.length) {
return;
}
i++;
const url = urls[index];
fetch(url)
.then((res) => {
ret[index] = res;
})
.catch((err) => {
ret[index] = err;
})
.finally(() => {
request(i++);
finned++;
});
}
for (let j = 0; j < max; j++) {
request(j);
}
}
- Async/await 版本
js
async function sendRequest(urls, max, callback) {
async function asyncPool() {
const ret = [];
const exec = [];
for (const url of urls) {
const p = Promise.resolve().then(() => fetch(url));
ret.push(p);
if (urls.length >= max) {
const t = p.then(() => exec.splice(exec.indexOf(t), 1));
exec.push(t);
if (exec.length >= max) {
await Promise.race(exec);
}
}
}
return await Promise.all(ret);
}
return await asyncPool();
}