前端基础笔试题&解答

实现浅克隆和深克隆

/**
 * 浅克隆
 * @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.stringifyJSON.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();
})
复制代码

实现 bindapplycall

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
喜欢就支持一下吧
点赞0 分享