方法实现原理

217 阅读2分钟

科里化

function curry(func) {            
    return function curriedFn(...args) {                
        //判断实参和形参的个数                
        if (args.length < func.length) {                    
            return function () {                        
                return curriedFn(args.concat(Array.from(arguments)))                    
            }                
        }            
    }        
}

组合函数

function compose(...args) {
    return function (value) {
        return args.reverse().reduce(function (acc, fn) {
            return fn(acc)
        }, value)
    }
}

new实现原理

function _new(Func, ...args) {    
    let obj = Object.create(Func.protoType);    
    let result = Func.call(obj, ...args);    
    if ((result !== null && typeof result === 'object') || (typeof result === 'function')) {        
        return result;    
    }    
    return obj;
}

深度克隆

function _type(value) {    
    return Object.prototype.toString.call(value);
}
function _deepClone(obj) {    
    // 如果是null直接返回null        
    if (obj === null) return null;    
    // 如果是基本数据值或者函数,也直接返回即可(函数无需克隆处理)        
    if (typeof obj !== 'object') return obj;    
    // 如果是正则        
    if (_type(obj) === '[object RegExp]') return new RegExp(obj);    
    // 如果是日期格式的数据        
    if (_type(obj) === '[object Date]') return new Date(obj);    
    // obj.constructor:找到的是所属类原型上的constructor,而原型上的constructor指向的是当前类本身 =>保证传递进来什么类型的值,我们最后创建的newObj也是对应类型的        
    let newObj = new obj.constructor;    
    for (let key in obj) {        
        if (!obj.hasOwnProperty(key)) break;        
        // 如果某一项的值是引用值吗,我们还需要进一步迭代循环,把引用值中的每一项也进一步克隆 =>深度克隆                
        newObj[key] = _deepClone(obj[key]);    
    }    
    return newObj;
}

发布订阅

class Sub {    
    constructor() {        
        this.$pond = [];    
    }    
    add(fn) {        
        let flag = this.$pond.some((item) => { 
           return item === fn       
        });        
        !flag && this.$pond.push(fn)    
    }    
    remove(fn) {        
        let $pond = this.$pond;        
        for (let i = 0; i < $pond.length; i++) {            
            let item = $pond[i];            
            if (item === fn) {                
                $pond[i] = null;            
            }        
        }    
    }    
    fire(...args) {        
        let $pond = this.$pond;        
        for (let i = 0; i < $pond.length; i++) {            
            let item = $pond[i];            
            if (typeof item !== "function") { 
                $pond.splice(i, 1);                
                i--;                
                continue;            
            }            
            item.call(this, ...args)        
        }    
    }
}

promise

class MyPromise {
    constructor(executor) {
        this.status = 'pending';
        this.value = undefined;
        this.resolveArr = [];
        this.rejectArr = [];
        let change = (status, value) => {
            if (this.status !== 'pending') return;
            this.value = value;
            this.status = status;
            let fnArr = status === 'resolved' ? this.resolveArr : this.rejectArr;
            fnArr.forEach(item => {
                if (typeof item !== 'function') return;
                item(this.value);
            });
        };
        let resolve = result => {
            if (this.resolveArr.length > 0) {
                change('resolved', result);
                return;
            }
            let delayTimer = setTimeout(_ => {
                change('resolved', result);
                clearTimeout(delayTimer);
            }, 0);
        };
        let reject = reason => {
            if (this.rejectArr.length > 0) {
                change('rejected', reason);
                return;
            }
            let delayTimer = setTimeout(_ => {
                change('rejected', reason);
                clearTimeout(delayTimer);
            }, 0);
        };
        try {
            executor(resolve, reject);
        } catch (err) {
            reject(err.message);
        }
    }
    then(resolveFn, rejectFn) {
        // 如果传递的参数不是函数(NULL/不传递),我们让成功或者失败顺延     
           if (typeof resolveFn !== 'function') {
            resolveFn = result => {
                return result;
            };
        }
        if (typeof rejectFn !== 'function') {
            rejectFn = reason => {
                return MyPromise.reject(reason);
            };
        }
        return new MyPromise((resolve, reject) => {
            this.resolveArr.push(result => {
                try {
                    let x = resolveFn(result);
                    if (x instanceof MyPromise) {
                        x.then(resolve, reject);
                        return;
                    }
                    resolve(x);
                } catch (err) {
                    reject(err.message);
                }
            });
            this.rejectArr.push(reason => {
                try {
                    let x = rejectFn(reason);
                    if (x instanceof MyPromise) {
                        x.then(resolve, reject);
                        return;
                    }
                    resolve(x);
                } catch (err) {
                    reject(err.message);
                }
            });
        });
    }
    // MyPromise.prototype.catch(fn) === MyPromise.prototype.then(null,fn)   
     catch (rejectFn) {
        return this.then(null, rejectFn);
    } /* 静态方法 */
    static resolve(result) {
        return new MyPromise(resolve => {
            resolve(result);
        });
    }
    static reject(reason) {
        return new MyPromise((_, reject) => {
            reject(reason);
        });
    }
    static all(arr) {
        return new MyPromise((resolve, reject) => {
            let index = 0,
                results = [];
            for (let i = 0; i < arr.length; i++) {
                let item = arr[i];
                if (!(item instanceof MyPromise)) continue;
                item.then(result => {
                    index++;
                    results[i] = result;
                    if (index === arr.length) {
                        resolve(results);
                    }

                }).catch(
                    reason => {
                        // 只要有一个失败,整体就是失败    
                                        reject(reason);
                    });
            }
        });
    }
}