这些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;
}
这里就差不多了,后面的我就直接上代码了
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;
};
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
};
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 || function(obj){
var F = function(){};
F.prototype = obj;
return new F();
}
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
}
}
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]
}
bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被bind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用。那bind创建的这个新函数还有其他什么特性吗?
sayColor() 调用 bind() 并传入对象 o ,创建了 o bjectSayColor() 函数。 object-SayColor() 函数的 this 值等于 o ,因此即使是在全局作用域中调用这个函数,bind与apply、call最大的区别就是:bind不会立即调用
你看,我一直在使用JavaScript中的bind()试验。事实证明,我们可以在多个场合,包括处理我几周前提到的闭包问题中,使用bind。
bind 和 apply,call 是 JS 修改 this 指向的三把利器 。对于 apply,call 来说,bind 的区别在于会返回一个修改了 this 指向的新函数,并不会立即执行。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!