call
我们先看个例子:
var obj = {
value: "贝小米",
};
function fn() {
console.log(this.value);
}
fn.call(obj); // 贝小米
call主要做了两件事:
- 改变 this 指向,由原来的window改为obj
- 执行 fn 函数
如果要自己写的话,先考虑改造 obj 对象:
var obj={
value:'贝小米',
fn:function() {
console.log( this.value );
}
}
obj.fn(); // '贝小米'
这里同样实现了 this 指向 obj 对象、执行 fn 函数两件事,但是在 obj 对象身上平白多了一个函数,这肯定不行,那就在函数调用完之后把它删除掉,用 delete obj.fn 实现。
obj.fn = fn;
obj.fn();
delete obj.fn;
按照这个思路我们就写出来了:
// 手写call(),根据原型链,每个函数都可以访问到这个我们自定义的方法啦,直接写function让别的函数的调用的话会报错。
Function.prototype.myCall = function ( context ) {
// 判断调用对象是不是函数,不是就直接抛出错误
if ( typeof this !== 'function' ) {
throw new Error("Type error");
}
// 获取参数,除了第一个参数(context中可枚举的属性)
let args = [...arguments].slice(1);
let result = null;
// 判断context是否有传值,没有则默认为window
context = context || window;
// 将被调用的方法设置为context的属性(修改this指向为context)
context.fn = this;
// 执行要被调用的方法(参数为传入的参数)
result = context.fn(...args);
// 删除手动增加的属性方法
delete context.fn;
// 返回执行结果
return result;
}
function testFun () {
console.log(this.name);
}
var name = '王五';
var obj = {
name: '贝小米',
};
testFun.myCall(obj); //'贝小米'
注意点:
1、我们手写的 myCall 方法要添加到构造函数 Function 的原型对象上,这个其他的函数才能使用这个方法,否则会报错,也就是第一句 Function.prototype.myCall = function () { };
bind
bind
有如下特性:
- 1、指定
this
- 2、传入参数
- 3、返回一个函数
- 4、柯里化【是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术,是闭包的一个应用】
例:fn(a,b,c) = > fn(a)(b)(c)