定义
相同点
- 这三个都是为了修改this指向的。
- 接受的第一个参数都是要绑定的this指向.
不同点
- apply的第二个参数是一个参数数组,而call和bind的第二个及之后的参数作为函数实参按顺序传入。
- call和apply会立即调用,而bind是返回一个已被改变this指向的新函数,对旧函数没有影响。
实现
手写call函数
问题:
- 函数定义的位置?
- call可以被任何函数调用,所以是在函数的prototype
- 如何显示绑定this?
- 可以将函数绑到对象上,那通过obj.fn这样调用时,函数的this就指向了obj
- 如何传参
- 通过arguments获取除index为0以外的参数
代码
Function.prototype.myCall = function(context) {
if(typeof this !== 'function) {
throw new TypeError('Error')
}
const ctx = context || window;
ctx.fn = this;
const arg = [...arguments].slice(1);
const res = arguments.length > 1 ? ctx.fn(...arg) : ctx.fn();
delete ctx.fn;
return res;
}
demo
const zhangsan = {
name: 'zhangsan',
getName: function() {
console.log(this.name)
}
}
const lisi = {
name: 'lisi'
}
console.log(zhangsan.getName.myCall(lisi))
手写apply函数
问题:
- 函数定义的位置?
- 如何显示绑定this?
- 如何传参
代码
Function.prototype.myApply = function(context) {
if(typeof !== 'function') {
throw new TypeError('Error')
}
const ctx = context || window;
ctx.fn = this;
const arg = argument[1];
const res = arg ? ctx.fn(...arg) : ctx.fn();
delete ctx.fn;
return res;
}
demo
const zhangsan = {
name: 'zhangsan',
getName: function() {
console.log(this.name)
}
}
const lisi = {
name: 'lisi'
}
console.log(zhangsan.getName.myApply(lisi))
手写bind函数
问题:
- 函数定义的位置?
- call可以被任何函数调用,所以是在函数的prototype
- 如何显示绑定this?
- 可以将函数绑到对象上,那通过obj.fn这样调用时,函数的this就指向了obj
- 如何传参
- bind函数返回一个绑定函数,最终调用需要传入函数实参和绑定函数的实参
代码
Function.prototype.myBind = function(context) {
if(typeOf this !==
throw new TypeError(
}
const ctx = context || window;
const arg = [...arguments].slice(1);
const _this = this;
return function F() {
//检测 New , 如果当前函数的this指向的是构造函数中的this 则判定为new 操作
if(this instanceOf F) {
return new _this(...ars, ...arguments)
}
return _this.applay(ctx, arg.contact(...arguments))
}
}
- bind返回一个函数,对于函数来说有两种方式调用,一种是直接调用,一种是通过new的方式,我们先来说直接调用的方式
- 对于直接调用来说,这里选择了apply的方式,但是对于参数需要注意以下情况:因为bind可以实现类似这样的代码 f.bind(obj,1)(2),所以我们需要将两边的参数拼接起来,于是就有了这样的实现args.concat(…arguments)
- new的方式,我们先判断this,对于new的情况,不会被任何方式改变this,所以对于这种情况我们需要忽略传入的this,此时this应该指向构造出的实例,而不是bind绑定的第一个参数
demo
function getName(name) {
this.name = name;
}
const animal = {};
let person = getName.myBind(animal);
person('人');
console.log(`animal.name`, animal.name);
const zhangsan = new person('zhangsan');
console.log(`zhangsan`, zhangsan);
console.log(`animal.name`, animal.name);
涉及到的知识点:
- error类型定义等
- arguments相关,
- typeOf和instanceOf
参考