Realize shallow clone and deep clone

/** * shallow clone *@param {*} val 
 */
function clone(val) {
    if (typeofval ! = ='object') return val;
    return {
        ...val
    };
}

/** * deep clone * 1. Date and RegExp require special processing * 2. Circular references also need to copy past * *@param {*} val 
 */
function deepClone(val, map = new WeakMap(a)) {
    if (val instanceof RegExp) return new RegExp(val);
    if (val instanceof Date) return new Date(val);
    if (val === null || typeofval ! = ='object') return val;
    if (map.has(val)) return map.get(val);
    const newObj = new val.constructor();
    map.set(val, newObj);
    for (const key in val) {
        if (val.hasOwnProperty(key)) {
            newObj[key] = deepClone(val[key], map)
        }
    }
    return newObj;
}


module.exports = {
    clone,
    deepClone
}
Copy the code

JEST:

const {
    clone,
    deepClone
} = require('.. /clone')



test("Shallow clone".() = > {
    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("Deep clone".() = > {
    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)
})


test("Test replication loop reference".() = > {
    const a = {
        aKey: 'aaaaa'
    }
    const b = {
        bKey: 'bbbbb'
    }
    a.bObj = b;
    b.aObj = a;

    const obj = {
        a,
        b
    };
    const obj1 = deepClone(obj);

    expect(obj1.a.bObj).toBe(obj1.b);
    expect(obj1.b.aObj).toEqual(obj1.a);
})

Copy the code

Implement a function that can currize a function

/** * returns a Currified function *@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
}
Copy the code

JEST:

const {
    curry
} = require('.. /curry');
const {
    expect
} = require('@jest/globals');

test("Currt Currization".() = > {
    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))})Copy the code

implementationnewThe keyword

/** * implements the new keyword *@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;

}
Copy the code

JEST:

test("Test your own implementation of 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())

})
Copy the code

implementationJSON.stringifyJSON.parse

const supportTypes = ['number'.'boolean'.'string'.'null'.'object']

/** * implement 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(', ')}} `
}

/** * Implements JSON. Parse *@param {s} string 
 */
function parse(string) {
    const fn = new Function(`return ${string}`);
    return fn();
}

module.exports = {
    stringify,
    parse
}
Copy the code

JEST TEST:

const {
    stringify,
    parse
} = require('.. /json')


test('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('test the 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))
})
Copy the code

Implement instanceof

/** * implement 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); }}Copy the code

JEST TEST:


test("InstanceOf test implementation".() = > {
    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(a); expect(instanceOf(reg,RegExp)).toBe(reg instanceof RegExp)
    expect(instanceOf(reg, Object)).toBe(reg instanceof Object)})Copy the code

implementationArray.prototype.reduce

/** * Implement 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
Copy the code

implementationdebounceImage stabilization function

/** * returns a buffered function * that will not be called until a timeout has elapsed since the last call@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('print', a)
}, 500)

debounceFunc(88);
debounceFunc(99);
setTimeout(() = > {
    debounceFunc(100);
}, 500)
/ / print 99
/ / print 1000
Copy the code

implementationthrottleThrottling function

/** * returns a throttled function * that calls func only once in time *@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('Throttle:', a, b)
}, 300)

throttleFunc(1.2)
throttleFunc(2.3)
throttleFunc(4.5)
setTimeout(() = > {
    throttleFunc(6.7)},300)

// Throttle: 1 2
// Throttle: 6, 7
Copy the code

implementationPromise

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) {
        setTimeout(() = > {
            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) {
        setTimeout(() = > {
            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) = > {
            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) = > {
            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) {
        setTimeout(() = > {
            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); }}}})module.exports = MyPromise

Copy the code

Jest test:

const MyPromise = require('./MyPromise');
// const MyPromise = Promise;

test('Error penetration'.done= > {
    const errorVal = 'wrong';
    new MyPromise((resolve, reject) = > {
            reject(errorVal)
        }).then()
        .catch()
        .then(() = > {})
        .catch((err) = >{ expect(err).toBe(errorVal) done(); })}); test('asynchronous promise'.done= > {
    const VAL = 888;
    new MyPromise((resolve) = > {
        setTimeout(() = > {
            resolve(VAL)
        }, 100)
    }).then((val) = > {
        expect(val).toBe(VAL)
        done()
    })
})

test(Promise to return Resolved state in 'then '.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 returns a promise in the Rejected state'.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 through'.done= > {
    const VAL = 888;
    new MyPromise((resolve, reject) = > {
            setTimeout(() = > {
                reject(VAL);
            }, 100)
        }).then()
        .then((val) = > {

        }).catch((val) = > {
            expect(val).toBe(VAL)
            done()
        })
})

test('catch through'.done= > {
    const VAL = 888;
    new MyPromise((resolve, reject) = > {
            setTimeout(() = > {
                resolve(VAL);
            }, 100)
        }).catch((val) = > {})
        .catch()
        .then((val) = > {
            expect(val).toBe(VAL)
            done()
        })
})

test('finally: synchronous 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: asynchronous 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: Throws an error '.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(); })})Copy the code

implementationPromise.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
}
Copy the code

JEST test:

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('Asynchronous 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 Awesome!;
        })
    }

    MyPromise.try(mydo)
        .then((res) = > {
            expect(res).toBe(Awesome!)
            expect(results[0]).toBe(999)
            expect(results[1]).toBe(888)
            done()
        })
    results.push(999);
});
Copy the code

implementationEventBus

class EventBus {
    constructor() {
        this.eventMap = new Map(a); }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 ofcallbackSet) { 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;
Copy the code

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();
})
Copy the code

implementationbind,applycall

function bind(func, thisArg) {
    const key = Symbol(a); thisArg[key] = func;return (. args) = >thisArg[key](... args) }function apply(func, thisArg, argArray) {
    if(! thisArg) thisArg = {};const key = Symbol(a); thisArg[key] = func;constresult = thisArg[key](... argArray)delete(thisArg, key)
    return result
}

function call(func, thisArg, ... argArray) {
    return apply(func, thisArg, argArray);
}


module.exports = {
    bind,
    apply,
    call
}
Copy the code

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: Awesome!
    })

    const obj2 = {
        value: 777,
        myDo
    }
    const obj3 = {
        value: 555,
        myDo
    }

    expect(obj2.myDo()).toBe(Awesome!)
    expect(obj3.myDo()).toBe(Awesome!)
    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()
});
Copy the code

To implement aschedulerThe scheduler

Note: The scheduler can add multiple tasks, but only a specified number of tasks can be executed simultaneously.

class Scheduler {
    constructor(num = 2) {
        this.limitNum = num;
        this.tasks = [];
        this.runNum = 0;
    }

    async run() {
        if (!this.tasks.length) {
            this.runNum = 0;
            return;
        }
        const num = this.limitNum - this.runNum
        const runTasks = this.tasks.splice(0, num);
        this.runNum += num
        await Promise.all(runTasks.map((task) = > task()))
        this.run();
    }

    add(fn, ... args) {
        return new Promise((resolve, reject) = > {
            const task = async() = > {try {
                    const res = awaitfn(... args) resolve(res) }catch (e) {
                    reject(e);
                } finally {
                    if (this.runNum > 0) {
                        this.runNum--; }}}this.tasks.push(task);
            if (this.runNum < this.limitNum) {
                this.run(); }}}})const scheduler = new Scheduler();

const timeout = (fn, time = 500) = > new Promise((resolve) = > {
    setTimeout(() = > {
        resolve(fn())
    }, time)
})

scheduler.add(() = > {
    console.log('sync-1')
}).then(() = > {
    console.log('sync-1-end')
})
scheduler.add(() = > {
    return timeout(() = > {
        console.log('async-1')
    })
}).then(() = > {
    console.log('async-1-end')
})


scheduler.add(() = > {
    return timeout(() = > {
        console.log('async-2')
    })
}).then(() = > {
    console.log('async-1-end')
})

scheduler.add(() = > {
    return timeout(() = > {
        console.log('async-3')
    })
}).then(() = > {
    console.log('async-2-end')
})

scheduler.add(() = > {
    return timeout(() = > {
        console.log('async-4')
    })
}).then(() = > {
    console.log('async-3-end')
})

scheduler.add(() = > {
    console.log('sync-2')
}).then(() = > {
    console.log('sync-2-end')})// sync-1
// sync-1-end
// async-1
// async-1-end
// async-2
// async-1-end
// async-3
// async-2-end
// async-4
// async-3-end
// sync-2
Copy the code

Implement an event delegate

<ul class="container">
    <li class="item">1231<span style="color: red">123131</span></li>
    <li class="item">8888</li>
    <li class="item">The third line</li>
    <li class="item"><div>In the fourth row</div></li>
</ul>

<script>
const container = document.querySelector(".container");

delegate(container, ".item"."click".(e, item) = > {
    console.log(item.textContent);
});

function delegate(container, itemSelector, event, handler) {
    container.addEventListener(event, (e) = > {
    let target = e.target;
        while(! target.matches(itemSelector) && target ! == container) { target = target.parentNode; }if (target !== container) {
            handler(e, target);
        }
    });
}
</script>
Copy the code

Implement a slider button using CSS

Description: only use a div to achieve a slider button, container height is fixed, width is not fixed, hover button, inside the slider from left to right, the process requires animation.

<div class="item-div"></div>
<style>
    .item-div {
    height: 50px;
    border: 1px solid red;
    position: relative;
    }
    .item-div::before {
    content: "";
    display: block;
    position: absolute;
    width: 50px;
    height: 50px;
    left: 0;
    background-color: blue;
    transition: all 0.5 s ease;
    }
    .item-div:hover {
    border-color: green;
    }
    .item-div:hover.item-div::before {
    margin-left: 100%;
    transform: translate(-100%);
    }
</style>
Copy the code

Implement a draggablediv

 <div class="box"></div>
<style>
      .box {
        position: absolute;
        width: 100px;
        background-color: red;
        height: 100px;
        left: 0;
        top: 0;
      }
</style>
<script>
      let lastPosition = [];
      const boxEle = document.querySelector(".box");
      let isDraging = false;
      boxEle.addEventListener("mousedown".(e) = > {
        isDraging = true;
        lastPosition[0] = e.clientX;
        lastPosition[1] = e.clientY;
      });
      document.addEventListener("mousemove".(e) = > {
        if(! isDraging)return;
        const deltaX = e.clientX - lastPosition[0];
        const deltaY = e.clientY - lastPosition[1];
        const curLeft = parseInt(boxEle.style.left || 0);
        const curTop = parseInt(boxEle.style.top || 0);
        boxEle.style.cssText = `left: ${curLeft + deltaX}px; top:${ curTop + deltaY }px`;

        lastPosition[0] = e.clientX;
        lastPosition[1] = e.clientY;
      });

      document.addEventListener("mouseup".() = > {
        isDraging = false;
      });
</script>
Copy the code

Implement arrayflatDeepfunction

/** * level-1: level-1: level-1: level-1: level-1: level-1: level-1: level-1: level-1: level-1@param {*} arr 
 * @param {*} level 
 */
function flatDeep(arr, level = 1) {
    returnlevel ! = =0 ?
        arr.reduce((res, item) = > Array.isArray(item) ? res.concat(flatDeep(item, level - 1)) : res.concat([item]), []) :
        arr.slice();
}


const arr = [1.2.3[5.6.7[9.10.11[12.13.14]]]]

console.log(flatDeep(arr))
/ / [1, 2, 3, 5, 6, 7, [9, 10, 11, [12, 13, 14]]]

console.log(flatDeep(arr, 2))
/ / [1, 2, 3, 5, 6, 7, 9, 10, 11, [12, 13, 14]]

console.log(flatDeep(arr, -1))
// [1, 2, 3, 5, 6,7, 9, 10, 11, 12,13, 14]
Copy the code

Implements a function that returns a function that determines the type of the object

// implement isType so that
const isFunction = isType('Function');
const isNumber = isType('Number');
const isArray = isType('Array');

console.log(isNumber(12))// true
console.log(isArray([])) // true

Copy the code

function isType(type) {
    return (val) = > Object.prototype.toString.call(val) === `[object ${type}] `
}

const isFunction = isType('Function');
const isArray = isType('Array');
const isNumber = isType('Number');

console.log(isFunction(12)) // false
console.log(isFunction(() = > {})) // true
console.log(isArray({})) // false
console.log(isArray([])) // true
console.log(isNumber(12)) // true
console.log(isNumber(true)) // false
Copy the code

Implementing composite inheritance

function Person(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}

Person.prototype.getInfo = function () {
    return `Name:The ${this.name}\nAge:The ${this.age}\nSex:The ${this.sex}`
}


function Student(name, age, sex, id) {
    Person.call(this, name, age, sex)
    this.id = id;
}

Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

Student.prototype.getStudentInfo = function () {
    const info = this.getInfo();
    return `${info}\nID:The ${this.id}`
}


const s1 = new Student('Per'.18.'man'.'9527');

console.log(s1.getInfo())
// Name:Per
// Age:18
// Sex:man

console.log(s1.getStudentInfo())
// Name:Per
// Age:18
// Sex:man
// ID:9527

console.log(s1 instanceof Student) // true
console.log(s1 instanceof Person) // true
Copy the code

Handwritten AJAX

const xmr = new XMLHttpRequest();

xmr.open('GET'.'/get/user'.true);

xmr.onreadystatechange = function () {
    if (xmr.readyState === 4 && xmr.status === 200) {
        console.log(xmr.response);

    }
}

xmr.send();

Copy the code

Implement trim with re

function trim(str) {
    return str.replace(/^\s+|\s+$/.' ');
}

console.log('1231231 234234')
console.log(trim('1231231 234234'))

/ / 1231231 234234
// 1231231  234234
Copy the code

handwrittenObject.create()

/** * implement obj. Create *@param {*} proto 
 */
function create(proto) {
    function Fn() {}
    Fn.prototype = proto;
    Fn.constructor = Fn;
    return new Fn();
}
Copy the code

test("The create test".() = > {
    const a = {
        aKey: 'aaaaa'.getVal() {
            return this.name; }}const obj1 = Object.create(a);
    const obj2 = create(a);
    obj1.aKey = 888;

    expect(obj1.__proto__.aKey).toBe(obj2.__proto__.aKey);
})

Copy the code

Hexadecimal conversion

/** * base conversion */
function convert(num, scale = 10) {
    if (scale === 10) return num.toString();
    const numStr = '0123456789ABCDEF';
    const stack = [];
    while (num) {
        stack.push(num % scale)
        num = (num / scale) | 0
    }
    let res = ' '
    for (const val of stack) {
        res = val + res;
    }
    return res;
}
Copy the code

const {
    convert

} = require('.. /convert')

test("Base conversion".() = > {
    const num = 888;
    expect(convert(num, 2)).toBe(num.toString(2))
    expect(convert(num, 3)).toBe(num.toString(3))
    expect(convert(num, 4)).toBe(num.toString(4))
    expect(convert(num, 5)).toBe(num.toString(5))
    expect(convert(num, 6)).toBe(num.toString(6))
    expect(convert(num, 7)).toBe(num.toString(7))
    expect(convert(num, 8)).toBe(num.toString(8))
    expect(convert(num, 9)).toBe(num.toString(9))
    expect(convert(num, 10)).toBe(num.toString(10))
    expect(convert(num, 11)).toBe(num.toString(11))
    expect(convert(num, 12)).toBe(num.toString(12))
    expect(convert(num, 16)).toBe(num.toString(16))})Copy the code

Adds a separator for the thousandth digit of a numeric string

function thousandth(str) {
    return str.replace(/\d(? = (? :\d{3})+(? :\.\d+|$))/g.'$&,);
}

console.log(thousandth('1123123123123123.3453'))
/ / 1123123123123123.3, 453
Copy the code

Refer to the link

21 high-frequency JavaScript handwritten interview questions for you