Js实现Call、apply、bind、Promise、Object.create、new、reduce

更新日期: 2019-08-29阅读: 1.9k标签: bind

手动实现Call

这些api的特点以及具体用法我就不介绍了,相信你如果奔着手动实现的方向来看,那么你一定对它很了解

核心: this永远指向最后调用它的对象

代码:

Function.prototype.myCall = function(context, ...args) {
    context['key'] = this;
    context.key(...args);
    delete context.key;
}

写到这里,call基本的特点已经实现,其实面试中一般写到这里也就通过了,但是实际上却还差很远。之前我的那篇文章也是如此,只是实现了基本的功能。因为完完全全的实现确实会花费很多时间.
还是简单说一下吧,我们知道call中是可以传入一些基本类型的,并且我们现在的这种实现方式增加了一个显示的key属性,实际上你在调用真正的call的时候去打印this是无法发现这些额外属性的,那么我们就仿照这些特性再去优化,接近一下

Function.prototype.myCall = function(context, ...args) {
    let newContext = context;
    if ([null, undefined].includes(context) ) {
        newContext = window || {};
    }
    switch (typeof context) {
        case 'number': {
            newContext = new Number(context);
            break;
        }
        case 'boolean': {
            newContext = new Boolean(context);
            break;
        }
        case 'string': {
            newContext = new String(context);
            break;
        }
    }

    Object.defineProperty(newContext, 'key', {
        value: this,
        configurable: true,
        enumerable: false,
    });
    newContext.key(...args);
    delete newContext.key;
}

这里就差不多了,后面的我就直接上代码了


实现apply

Function.prototype.myApply = function(context, obj) {
    if (typeof obj !== 'object') {
        throw new TypeError('CreateListFromArrayLike called on non-object')
    }
    let newContext = context;
    if ([null, undefined].includes(context)) {
        newContext = window;
    }
    switch (typeof context) {
        case 'number': {
            newContext = new Number(context);
            break;
        }
        case 'boolean': {
            newContext = new Boolean(context);
            break;
        }
        case 'string': {
            newContext = new String(context);
            break;
        }
    }
    Object.defineProperty(newContext, 'key', {
        value: this,
        configurable: true,
        enumerable: false,
    });
    newContext.key(...obj);
    delete newContext.key;
};


实现bind

Function.prototype.myBind = function(context, ...args) {
    let _this = this;
    let newFun = (...args2) => {
        _this.call(context, ...args, ...args2)
    };
    newFun.prototype = Object.create(_this.prototype)
    return newFun
};


实现Promise

function Promi(executor) {
    let _this = this;
    _this.$$status = 'pending';
    _this.failCallBack = undefined;
    _this.successCallback = undefined;
    _this.error = undefined;
    setTimeout(_ => {
        try {
            executor(_this.onResolve.bind(_this), _this.onReject.bind(_this))
        } catch (e) {
            _this.error = e;
            if (_this.callBackDefer && _this.callBackDefer.fail) {
                _this.callBackDefer.fail(e)
            } else if (_this._catch) {
                _this._catch(e)
            } else {
                throw new Error('un catch')
            }
        }
    })
}

Promi.prototype = {
    constructor: Promi,
    onResolve: function(params) {
        if (this.$$status === 'pending') {
            this.$$status = 'success';
            this.resolve(params)
        }
    },
    resolve: function(params) {
        let _this = this;
        let successCallback = _this.successCallback;
        if (successCallback) {
            _this.defer(successCallback.bind(_this, params));
        }
    },
    defer: function(callBack) {
        let _this = this;
        let result;
        let defer = _this.callBackDefer.success;
        if (_this.$$status === 'fail' && !_this.catchErrorFunc) {
            defer = _this.callBackDefer.fail;
        }
        try {
            result = callBack();
        } catch (e) {
            result = e;
            defer = _this.callBackDefer.fail;
        }
        if (result && result instanceof Promi) {
            result.then(_this.callBackDefer.success, _this.callBackDefer.fail);
            return '';
        }
        defer(result)
    },
    onReject: function(error) {
        if (this.$$status === 'pending') {
            this.$$status = 'fail';
            this.reject(error)
        }
    },
    reject: function(error) {
        let _this = this;
        _this.error = error;
        let failCallBack = _this.failCallBack;
        let _catch = _this._catch;
        if (failCallBack) {
            _this.defer(failCallBack.bind(_this, error));
        } else if (_catch) {
            _catch(error)
        } else {
            setTimeout(_ => { throw new Error('un catch promise') }, 0)
        }
    },
    then: function(success = () => {}, fail) {
        let _this = this;
        let resetFail = e => e;
        if (fail) {
            resetFail = fail;
            _this.catchErrorFunc = true;
        }
        let newPromise = new Promi(_ => {});
        _this.callBackDefer = {
            success: newPromise.onResolve.bind(newPromise),
            fail: newPromise.onReject.bind(newPromise)
        };
        _this.successCallback = success;
        _this.failCallBack = resetFail;
        return newPromise
    },
    catch: function(catchCallBack = () => {}) {
        this._catch = catchCallBack
    }
};   


// 测试代码

task()
    .then(res => {
        console.log('1:' + res)
        return '第一个then'
    })
    .then(res => {
        return new Promi(res => {
            setTimeout(_ => res('第二个then'), 3000)
        })
    }).then(res => {
        console.log(res)
   })
    .then(res => {
        return new Promi((suc, fail) => {
            setTimeout(_ => {
                fail('then失败')
           }, 400)
        })
    })
    .then(res => {
        console.log(iko)
   })
    .then(_ => {}, () => {
       return new Promi(function(res, rej) {
           setTimeout(_ => rej('promise reject'), 3000)
       })
   })
    .then()
    .then()
    .then(_ => {},
        rej => {
            console.log(rej);
            return rej + '处理完成'
        })
    .then(res => {
        console.log(res);
        // 故意出错
        console.log(ppppppp)
    })
    .then(res => {}, rej => {
        console.log(rej);
        // 再次抛错
        console.log(oooooo)
    }).catch(e => {
        console.log(e)
   })



实现Object.create

Object.create = Object.create || function(obj){

    var F = function(){};

    F.prototype = obj;

    return new F();

}  


实现new

function myNew(fun) {
    if (typeof fun !== 'function') throw new TypeError('fun is not a constructor')
    return function() {
        let obj = { '__proto__': fun.prototype }
        fun.call(obj, ...arguments)
        return obj
    }
}


实现reduce

Array.prototype.myReduce = function(fn, orginal = '__orginal') {
    let copy = [...this]
    if (orginal !== '__orginal') {
        copy.unshift(orginal)
    }
    while (copy.length > 1) {
        let prev = copy.shift()
        let next = copy.shift()
        copy.unshift(fn(prev, next))
    }
    return copy[0]
}


链接: https://www.fly63.com/article/detial/5591

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!