实现浅克隆和深克隆
/**
* 浅克隆
* @param {*} val
*/
function clone(val) {
if (typeof val !== 'object') return val;
return {
...val
};
}
/**
* 深克隆
* @param {*} val
*/
function deepClone(val) {
if (typeof val !== 'object') return val;
const isArr = val instanceof Array;
const res = isArr ? [] : {};
for (let key in val) {
res[key] = typeof val[key] === 'object' ? deepClone(val[key]) : val[key];
}
return res;
}
module.exports = {
clone,
deepClone
}
复制代码
JEST:
const {
clone,
deepClone
} = require('../clone')
test("浅克隆", () => {
const obj = {
a: {
b: 12
},
c: 23
};
const obj1 = clone(obj);
expect(obj1 === obj).toBe(false);
expect(obj1.a === obj.a).toEqual(true);
obj.a.b = 888;
expect(obj1.a.b).toBe(888)
})
test("深克隆", () => {
const obj = {
a: {
b: 12
},
c: 23
};
const obj1 = deepClone(obj);
expect(obj1 === obj).toBe(false);
expect(obj1.a === obj.a).toEqual(false);
obj.a.b = 888;
expect(obj1.a.b).toBe(12)
})
复制代码
实现一个能将函数柯里化的函数
/**
* 返回一个柯里化的函数
* @param {*} fn
* @param {*} args
*/
function curry(fn) {
const args = arguments[1] || []
return function () {
const newArgs = args.concat([...arguments])
if (fn.length > newArgs.length) {
return curry.call(this, fn, newArgs)
} else {
return fn.apply(this, newArgs);
}
}
}
module.exports = {
curry
}
复制代码
JEST:
const {
curry
} = require('../curry');
const {
expect
} = require('@jest/globals');
test("currt 柯里化", () => {
function add(a, b, c) {
return a + b + c;
}
const curryAdd = curry(add);
expect(curryAdd(1)(2, 3)).toBe(add(1, 2, 3))
expect(curryAdd(1, 2)(3)).toBe(add(1, 2, 3))
expect(curryAdd(1)(2)(3)).toBe(add(1, 2, 3))
})
复制代码
实现 new
关键字
/**
* 实现new 关键字
* @param {*} constructor
* @param {...any} args
*/
function newObj(constructor, ...args) {
const obj = {};
Object.setPrototypeOf(obj, constructor.prototype);
const res = constructor.apply(obj, args);
return typeof res === 'object' ? res : obj;
}
复制代码
JEST:
test("测试自己实现的new", () => {
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.getInfo = function () {
return this.name + this.age;
}
const person = new Person('hello', 18);
const person1 = newObj(Person, 'hello', 18);
expect(person1.name).toEqual(person.name)
expect(person1.age).toBe(person.age)
expect(person1.getInfo()).toEqual(person.getInfo())
})
复制代码
实现 JSON.stringify
和 JSON.parse
const supportTypes = ['number', 'boolean', 'string', 'null', 'object']
/**
* 实现JSON.stringify
* @param {*} obj
*/
function stringify(obj) {
const type = typeof obj;
if (!supportTypes.includes(type)) return undefined;
if (type === 'string') return `\"${obj}\"`;
if (type !== 'object' || obj === null) return `${obj}`;
if (Array.isArray(obj)) {
const arr = obj.map((val) => supportTypes.includes(typeof val) ? stringify(val) : 'null')
return `[${arr.toString()}]`
}
const res = []
for (const key in obj) {
const valueType = typeof obj[key];
if (!supportTypes.includes(valueType)) continue;
res.push(`"${key}":${stringify(obj[key])}`)
}
return `{${res.join(',')}}`
}
/**
* 实现JSON.parse
* @param {s} string
*/
function parse(string) {
const fn = new Function(`return ${string}`);
return fn();
}
module.exports = {
stringify,
parse
}
复制代码
JEST TEST:
const {
stringify,
parse
} = require('../json')
test('测试stringify', () => {
expect(stringify(12)).toEqual(JSON.stringify(12))
expect(stringify(true)).toEqual(JSON.stringify(true))
expect(stringify(false)).toEqual(JSON.stringify(false))
expect(stringify(null)).toEqual(JSON.stringify(null))
expect(stringify(undefined)).toEqual(JSON.stringify(undefined))
expect(stringify("1231")).toEqual(JSON.stringify("1231"))
function fn() {}
expect(stringify(fn)).toEqual(JSON.stringify(fn))
class Cls {}
expect(stringify(Cls)).toEqual(JSON.stringify(Cls))
const sym = Symbol('sym')
expect(stringify(sym)).toEqual(JSON.stringify(sym))
const arr = [null, undefined, Symbol(), 12, 34, {
a: 12
}, {
b: true,
[Symbol()]: 999,
abc: [12, 23]
}]
expect(stringify(arr)).toEqual(JSON.stringify(arr))
const obj = {
number: 12,
digit: 3.14159,
boolean: true,
boolean1: false,
a: undefined,
b: "1231",
[Symbol()]: 'hell',
arr,
fn: function () {},
y: Symbol(),
}
expect(stringify(obj)).toEqual(JSON.stringify(obj))
})
test('测试parse', () => {
const arr = [null, undefined, Symbol(), 12, 34, {
a: 12
}, {
b: true,
[Symbol()]: 999,
abc: [12, 23]
}]
const arrStr = JSON.stringify(arr);
expect(parse(arrStr)).toEqual(JSON.parse(arrStr))
const obj = {
number: 12,
digit: 3.14159,
boolean: true,
boolean1: false,
a: undefined,
b: "1231",
[Symbol()]: 'hell',
arr,
fn: function () {},
y: Symbol(),
}
const objStr = JSON.stringify(obj)
expect(parse(objStr)).toEqual(JSON.parse(objStr))
})
复制代码
实现instanceof
/**
* 实现 instanceOf
* @param {*} obj
* @param {*} constructor
*/
function instanceOf(obj, constructor) {
if (!constructor || !obj) return false;
let prototype = Object.getPrototypeOf(obj);
const constructorProto = constructor.prototype;
while (true) {
if (prototype === constructorProto) return true;
if (!prototype) return false;
prototype = Object.getPrototypeOf(prototype);
}
}
复制代码
JEST TEST:
test("测试实现的instanceOf", () => {
const obj = {};
expect(instanceOf(obj, Object)).toBe(obj instanceof Object)
const arr = []
expect(instanceOf(arr, Array)).toBe(arr instanceof Array)
expect(instanceOf(arr, Object)).toBe(arr instanceof Object)
const reg = new RegExp();
expect(instanceOf(reg, RegExp)).toBe(reg instanceof RegExp)
expect(instanceOf(reg, Object)).toBe(reg instanceof Object)
})
复制代码
实现 Array.prototype.reduce
/**
* 实现reduce
* @param {*} arr
* @param {*} callback
* @param {*} initialVal
*/
function reduce(arr, callback, initialVal) {
for (let i = 0; i < arr.length; i++) {
initialVal = callback(initialVal, arr[i], i, arr);
}
return initialVal;
}
const arr = [1, 2, 4, 5];
console.log(reduce(arr, (res, val) => res + val, 1)) // 13
复制代码
实现debounce
防抖函数
/**
* 返回一个已防抖函数
* 该函数自上一次调用后,间隔timeout时间才会调用 func
* @param {*} func
* @param {*} timeout
*/
function debounce(func, timeout) {
let handler;
return function (...props) {
clearTimeout(handler)
handler = setTimeout(() => {
func(...props);
}, timeout)
}
}
const debounceFunc = debounce((a) => {
console.log('打印', a)
}, 500)
debounceFunc(88);
debounceFunc(99);
setTimeout(() => {
debounceFunc(100);
}, 500)
// 打印 99
// 打印 1000
复制代码
实现throttle
节流函数
/**
* 返回一个已节流函数
* 该函数在 time 时间内只会调用 func 一次
* @param {*} func
* @param {*} time
*/
function throttle(func, time) {
let canRun = true;
return (...params) => {
if (!canRun) return;
canRun = false;
func(...params);
setTimeout(() => {
canRun = true;
}, time)
}
}
const throttleFunc = throttle((a, b) => {
console.log('节流:', a, b)
}, 300)
throttleFunc(1, 2)
throttleFunc(2, 3)
throttleFunc(4, 5)
setTimeout(() => {
throttleFunc(6, 7)
}, 300)
// 节流: 1 2
// 节流: 6 7
复制代码
实现 Promise
class MyPromise {
constructor(func) {
this.status = 'pending'
this.result = undefined;
this.error = undefined;
this.resoledCallbacks = [];
this.rejectedCallbacks = [];
const resolve = (result) => {
this.status = 'resolved'
this.result = result;
setTimeout(() => {
this.resoledCallbacks.forEach((callback) => callback())
})
};
const reject = (error) => {
this.status = 'rejected'
this.error = error;
setTimeout(() => {
this.rejectedCallbacks.forEach((callback) => callback())
})
};
try {
func && func(resolve, reject);
} catch (err) {
this.status = 'rejected';
this.error = err;
}
}
onResolve(callback, resolve, reject) {
if (!callback) return resolve();
try {
const result = callback(this.result);
if (result instanceof MyPromise) {
result.then((res) => {
resolve(res);
}).catch((err) => {
reject(err);
})
} else if (result instanceof Object && result.then instanceof Function) {
result.then(res => {
resolve(res);
})
} else {
resolve(result);
}
} catch (err) {
reject(err)
}
}
onReject(callback, resolve, reject) {
if (!callback) return reject(this.error);
try {
const res = callback(this.error);
resolve(res)
} catch (err) {
reject(err);
}
}
then(resolveCallback, rejectedCallback) {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
if (this.status === 'resolved') {
this.onResolve(resolveCallback, resolve, reject);
} else if (this.status === 'rejected') {
this.onReject(rejectedCallback, resolve, reject);
} else {
this.resoledCallbacks.push(() => this.onResolve(resolveCallback, resolve, reject));
this.rejectedCallbacks.push(() => this.onReject(rejectedCallback, resolve, reject));
}
})
})
}
catch (callback) {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
if (this.status === 'resolved') {
resolve(this.result);
} else if (this.status === 'rejected') {
this.onReject(callback, resolve, reject);
} else {
this.resoledCallbacks.push(() => resolve(this.result));
this.rejectedCallbacks.push(() => this.onReject(callback, resolve, reject));
}
})
})
}
onFinally(callback, resolve, reject) {
try {
callback && callback();
if (this.status === 'resolved') resolve(this.result);
if (this.status === 'rejected') reject(this.error);
} catch (err) {
reject(err)
}
}
/**
*
* @param {*} callback
*/
finally(callback) {
return new MyPromise((resolve, reject) => {
if (this.status === 'pending') {
this.resoledCallbacks.push(() => this.onFinally(callback, resolve, reject));
this.rejectedCallbacks.push(() => this.onFinally(callback, resolve, reject));
} else {
this.onFinally(callback, resolve, reject);
}
})
}
}
复制代码
Jest 测试:
const MyPromise = require('./MyPromise');
// const MyPromise = Promise;
test('错误穿透', done => {
const errorVal = '错误';
new MyPromise((resolve, reject) => {
reject(errorVal)
}).then()
.catch()
.then(() => {})
.catch((err) => {
expect(err).toBe(errorVal)
done();
})
});
test('异步promise', done => {
const VAL = 888;
new MyPromise((resolve) => {
setTimeout(() => {
resolve(VAL)
}, 100)
}).then((val) => {
expect(val).toBe(VAL)
done()
})
})
test('then中返回resolved 状态 的promise', done => {
const VAL = 888;
new MyPromise((resolve) => {
resolve(VAL)
}).then((val) => {
return new MyPromise((resolve) => {
setTimeout(() => {
resolve(val);
}, 100)
})
}).then((val) => {
expect(val).toBe(VAL)
done()
})
})
test('then中返回rejected状态的promise', done => {
const VAL = 888;
new MyPromise((resolve) => {
resolve(VAL)
}).then((val) => {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
reject(val);
}, 100)
})
}).then((val) => {
}).catch((val) => {
expect(val).toBe(VAL)
done()
})
})
test('then穿透', done => {
const VAL = 888;
new MyPromise((resolve, reject) => {
setTimeout(() => {
reject(VAL);
}, 100)
}).then()
.then((val) => {
}).catch((val) => {
expect(val).toBe(VAL)
done()
})
})
test('catch 穿透', done => {
const VAL = 888;
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(VAL);
}, 100)
}).catch((val) => {})
.catch()
.then((val) => {
expect(val).toBe(VAL)
done()
})
})
test('finally: 同步resolve', done => {
const VAL = 999;
new MyPromise((resolve, reject) => {
resolve(VAL)
}).finally((val) => {
expect(val).toBeUndefined();
}).catch((err) => {}).then((val) => {
expect(val).toBe(VAL)
done();
})
})
test('finally: 异步resolve', done => {
const VAL = 999;
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(VAL)
}, (100));
})
.finally((val) => {
expect(val).toBeUndefined();
})
.catch((err) => {})
.then((val) => {
expect(val).toBe(VAL)
done();
})
})
test('finally: 抛出错误', done => {
const VAL = '999';
new MyPromise((resolve, reject) => {
resolve()
})
.finally((val) => {
throw new Error(VAL)
})
.then((val) => {
})
.catch((err) => {
expect(err.message).toBe(VAL)
done();
})
})
复制代码
实现 Promise.all
, Promise.race
, Promise.allSelected
, Promise.any
, Promise.resolve
, Promise.reject
, Promise.try
function resolve(val) {
if (val instanceof Promise) return val;
if (val && val.then instanceof Function) return new Promise(val.then);
return new Promise((resolve) => resolve(val));
}
function reject(val) {
return new Promise((resolve, reject) => reject(val))
}
function all(promises) {
promises = promises.map((promise) => resolve(promise))
const results = []
let count = 0;
return new Promise((resolve, reject) => {
promises.forEach((promise, index) => {
promise.then((result) => {
results[index] = result;
count++;
if (count === promises.length) {
resolve(results);
}
}).catch((err) => {
reject(err);
})
});
})
}
function race(promises) {
let isPending = true;
return new Promise(
(resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
if (!isPending) break;
promises[i].then((result) => {
isPending = false;
resolve(result)
}).catch((err) => {
isPending = false;
reject(err)
})
}
}
)
}
function allSelected(promises) {
const results = []
let count = 0;
const check = (resolve) => {
count++;
if (count === promises.length) {
resolve(results);
}
}
return new Promise((resolve, reject) => {
promises.forEach((promise, index) => {
promise.then((result) => {
results[index] = {
status: 'fulfilled',
value: result
};
check(resolve);
}).catch((err) => {
results[index] = {
status: 'rejected',
reason: err
}
check(resolve)
})
});
})
}
function any(promises) {
const errors = []
let count = 0;
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then((result) => {
resolve(result)
}).catch((err) => {
errors[i] = err;
count++;
if (count === promises.length) {
reject(errors)
}
})
}
})
}
function myTry(callback) {
return new Promise((resolve, reject) => {
resolve(callback())
})
}
module.exports = {
resolve,
reject,
all,
race,
allSelected,
any,
try: myTry
}
复制代码
JEST 测试:
const MyPromise = require('../promiseStatic');
// const MyPromise = Promise
test('Promise.reject', done => {
const p = Promise.resolve(999)
MyPromise.reject(p).catch((err) => {
expect(err).toBe(p)
done()
})
})
test('Promise all', done => {
const RESULTS = [888, 999, 1000, 1111, 2222]
const p1 = new Promise((resolve, reject) => {
resolve(RESULTS[0])
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(RESULTS[1]);
}, 300)
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(RESULTS[2])
}, (500));
})
const p4 = {
then(resolve) {
resolve(RESULTS[3])
}
}
const p5 = RESULTS[4];
MyPromise.all([p1, p2, p3, p4, p5]).then((res) => {
res.forEach((r, index) => {
expect(r).toBe(RESULTS[index])
})
done();
})
});
test('Promise race', done => {
const RESULTS = [888, 999, 1000, 1111, 2222]
MyPromise.race([
Promise.resolve(RESULTS[0]),
Promise.resolve(RESULTS[1]),
Promise.resolve(RESULTS[2]),
Promise.resolve(RESULTS[3]),
]).then((res) => {
expect(res).toBe(RESULTS[0])
done();
})
});
test('异步Promise race', done => {
const RESULTS = [888, 999, 1000]
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(RESULTS[0])
}, (100));
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(RESULTS[1])
}, (200));
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(RESULTS[2])
}, (300));
})
MyPromise.race([p1, p2, p3]).then((res) => {
expect(res).toBe(RESULTS[0])
done();
})
});
test('Promise race reject', done => {
const RESULTS = [888, 999, 1000]
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(RESULTS[0])
}, (100));
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(RESULTS[1])
}, (200));
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(RESULTS[2])
}, (300));
})
MyPromise.race([p1, p2, p3])
.then((res) => {})
.catch((err) => {
expect(err).toBe(RESULTS[0])
done()
})
});
test('Promise allSelected', done => {
const RESULTS = [888, 999, 1000]
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(RESULTS[0])
}, (100));
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(RESULTS[1])
}, (200));
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(RESULTS[2])
}, (300));
})
MyPromise.allSelected([p1, p2, p3])
.then(([r1, r2, r3]) => {
expect(r1.status).toBe('rejected')
expect(r1.reason).toBe(RESULTS[0])
expect(r2.status).toBe('fulfilled')
expect(r2.value).toBe(RESULTS[1])
expect(r3.status).toBe('fulfilled')
expect(r3.value).toBe(RESULTS[2])
done()
})
});
test('Promise any', done => {
const RESULTS = [888, 999, 1000]
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(RESULTS[0])
}, (100));
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(RESULTS[1])
}, (200));
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(RESULTS[2])
}, (300));
})
MyPromise.any([p1, p2, p3])
.then((res) => {
expect(res).toBe(RESULTS[1])
done()
})
});
test('Promise any reject', done => {
const RESULTS = [888, 999, 1000]
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(RESULTS[0])
}, (100));
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(RESULTS[1])
}, (200));
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(RESULTS[2])
}, (300));
})
MyPromise.any([p1, p2, p3])
.catch((res) => {
res.forEach((r, index) => {
expect(r).toBe(RESULTS[index])
})
done()
})
});
test('Promise try', done => {
const results = [];
const mydo = () => {
results.push(888)
}
MyPromise.try(mydo)
.then((res) => {
expect(results[0]).toBe(888)
expect(results[1]).toBe(999)
done()
})
results.push(999);
});
test('Promise try async', done => {
const results = [];
const mydo = () => {
return Promise.resolve().then(() => {
results.push(888)
return 666;
})
}
MyPromise.try(mydo)
.then((res) => {
expect(res).toBe(666)
expect(results[0]).toBe(999)
expect(results[1]).toBe(888)
done()
})
results.push(999);
});
复制代码
实现 EventBus
class EventBus {
constructor() {
this.eventMap = new Map();
}
on(name, callback) {
if (this.eventMap.has(name)) {
this.eventMap.get(name).add(callback)
} else {
this.eventMap.set(name, new Set([callback]))
}
}
emit(name, ...args) {
const callbackSet = this.eventMap.get(name);
if (callbackSet) {
for (const callback of callbackSet) {
callback(...args);
}
}
}
off(name, callback) {
const callbackSet = this.eventMap.get(name);
if (!callbackSet) return false;
if (callback) {
callbackSet.delete(callback)
} else {
this.eventMap.delete(name)
}
}
once(name, callback) {
const handle = (...args) => {
callback(...args);
this.off(name, handle)
}
this.on(name, handle);
}
}
module.exports = EventBus;
复制代码
JEST TEST:
const EventBus = require('../EventBus');
test('on emit', done => {
const eventBus = new EventBus();
const name = 'hello'
const ARGS = [1, 2]
eventBus.on(name, (...args) => {
ARGS.forEach((val, index) => {
expect(args[index]).toBe(val);
})
})
eventBus.on(name, (...args) => {
ARGS.forEach((val, index) => {
expect(args[index]).toBe(val);
})
})
eventBus.emit(name, ...ARGS);
done();
});
test('on off', done => {
const eventBus = new EventBus();
const name = 'hello'
const ARGS = [1, 2]
let result = []
const handle = (...args) => {
result = args;
}
eventBus.on(name, handle)
eventBus.emit(name, ...ARGS);
expect(result).toStrictEqual(ARGS);
done();
});
test('on off1', done => {
const eventBus = new EventBus();
const name = 'hello'
const ARGS = [1, 2]
let result = []
const handle = (...args) => {
result = args;
}
eventBus.on(name, handle)
eventBus.off(name, handle)
eventBus.emit(name, ...ARGS);
expect(result.length).toBe(0);
done();
});
test('once', (done) => {
const eventBus = new EventBus();
const name = 'hello'
let result = 0
const handle = () => {
result++;
}
eventBus.once(name, handle)
eventBus.emit(name);
eventBus.emit(name);
expect(result).toBe(1);
done();
})
test('once2', (done) => {
const eventBus = new EventBus();
const name = 'hello'
let result = 0
const handle = () => {
result++;
}
eventBus.on(name, handle)
eventBus.emit(name);
eventBus.emit(name);
expect(result).toBe(2);
done();
})
复制代码
实现 bind
、apply
和 call
function bind(func, thisArg) {
const key = Symbol();
thisArg[key] = func;
return (...args) => thisArg[key](...args)
}
function apply(func, thisArg, argArray) {
if (!thisArg) thisArg = {};
const key = Symbol();
thisArg[key] = func;
const result = thisArg[key](...argArray)
delete(thisArg, key)
return result
}
function call(func, thisArg, ...argArray) {
return apply(func, thisArg, argArray);
}
module.exports = {
bind,
apply,
call
}
复制代码
JEST TEST:
const {
bind,
apply,
call
} = require('../bind')
test('bind', done => {
function myDo() {
return this.value;
}
const obj = {
value: 888,
myDo
}
expect(obj.value).toBe(obj.myDo())
const obj1 = {
value: 999,
myDo
}
expect(obj1.value).toBe(obj1.myDo())
myDo = bind(myDo, {
value: 666
})
const obj2 = {
value: 777,
myDo
}
const obj3 = {
value: 555,
myDo
}
expect(obj2.myDo()).toBe(666)
expect(obj3.myDo()).toBe(666)
done()
});
test('apply', done => {
function myDo(a, b) {
return this.value + a + b;
}
const obj = {
value: 1
}
expect(apply(myDo, obj, [2, 3])).toBe(6)
expect(apply(myDo, null, [2, 3])).toBe(NaN)
expect(call(myDo, {
value: 2
}, 2, 3)).toBe(7)
done()
});
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END