在写bind函数之前,先来了解一下什么是bind函数。引用MDN的一句话来说:
bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
简单来说:bind是一个绑定了this的新函数,它跟apply、call一样都是改变this指向的,但唯一区别是bind函数不会立刻执行,需要进行函数调用才能执行;
简单举个栗子:
let obj1 = {
num: 1
};
let obj2 = {
num: 2
}
function fn (x,y) {
console.log(x+y+this.num);
}
fn.call(obj1,1,2); // 4
fn.apply(obj1,[1,2]); // 4
let _fn = fn.bind(obj1,1);
_fn(2); // 4
总结一下bind的特点:
1、改变this指向;
2、返回了一个绑定了this的新函数;
3、支持函数柯里化:我们在调用_fn之前传入了一部分参数,调用时参入了剩余参数;
函数柯里化:简单来说就是一个函数传入部分参数,返回一个新函数处理剩余的参数;
举个栗子:
function fn (x,y) {
return function(y) {
console.log(x+y);
}
}
let _fn = fn(1);
_fn(2); // 3
fn(1)(2); // 3
下面简单来实现以下bind函数:
Function.prototype._bind = function(obj) {
let fn = this;
return function() {
fn.call(obj);
}
}
let obj = {
num: 1
}
function fn() {
console.log(this.num);
}
let _fn = fn._bind(obj);
_fn();// 4
上面这个bind函数简单实现了改变this, let fn = this; 这一行代码注意一下,如果不保存this,this是指向window; 但是有一个问题: 不支持传入参数,下面来完善一下:
Function.prototype._bind = function (obj) {
// 从第1位裁剪数据,因为第0位是this;
let args = Array.prototype.slice.call(arguments,1);
let fn = this;
return function() {
fn.apply(obj,args);
}
}
let obj = {
num: 1
}
function fn(x) {
console.log(x+this.num);
}
let _fn = fn._bind(obj,1);
_fn();// 2
上面代码实现了参数传递,但是还不算完美,因为之前说过bind函数支持函数柯里化,在完善一下:
Function.prototype._bind = function(obj) {
// 从第1位裁剪数据,因为第0位是this;
let args = Array.prototype.slice.call(arguments,1);
let fn = this;
return function() {
// 截取剩余参数
let params = Array.prototype.slice.call(arguments);
fn.apply(obj,args.concat(params));
}
}
let obj = {
num: 1
}
function fn (x,y) {
console.log(x+y+this.num);
}
let _fn = fn._bind(obj,1);
_fn(2); // 4
函数柯里化的方式实现了bind函数,这里注意的是concat合并参数的时候args在前,params在后,顺序不能搞错这样参数的顺序才对;
完。