最好先知道的知识:
①call和apply
②闭包以及闭包的传参
③原型链
bind方法干什么的
准确来说是Function.prototype.bind()
方法,这是函数原型对象的方法。
我们都知道,函数里面的this指向向来也是一门学问。当我们想要改变这个this指向的时候,有没有什么好办法呢?
bind()方法主要就是将函数绑定到某个对象(当然包括某个函数),bind()会创建一个绑定了一个新的this的函数,函数体内的this对象的值会被绑定到传入bind()第一个参数的值,而其余参数将作为新函数的参数,供调用时使用。
例如,func.bind(obj)
相当于obj.f()
,这一点和call()
很像,不同的是返回的是函数,不会立即执行!(下文有例子区别)
传入参数
调用绑定函数时作为this 传递给目标函数
添加到绑定函数参数列表中的参数
返回值
返回一个原函数的拷贝,并拥有指定的this值和初始参数。
深拷贝
var foo = function(){console.log("你很勇哦")}
var A= foo.bind()
var B= foo.bind()
console.log(A===B) //false
A()//你很勇哦
B()//你很勇哦
可以看到虽然了A、B两个函数使用了foo.bind()进行拷贝,但是两者是两个独立的函数,在两个不同的内存地址中
函数调用,改变this
var obj = {name:"代码人"}
var foo = function(){
return this;//返回this
}
var A= foo.bind(obj)
var B= foo.bind(obj)
console.log(A()===B())//true this指向同一个obj
//记得【调用】
this.name = "window"
var obj = {
name: "obj",
getName: function() { console.log(this.name); }
}
obj.getName() //obj,对象函数this指向调用对象本身
var A= obj.getName //非严格模式下一般函数的this值window
A() //window
A.bind(obj)() //obj 重新绑定了this
接收多个参数,柯里化形式传参 fn(1)(2)
function func(y, z){
console.log( this.x);//这个函数没有x属性,咱们得另外绑定this
console.log( y );
console.log( z );
}
var obj={x:1}//一个有x属性的对象
var A =func.bind(obj,2,3)//像call一样的传参方式
A()//1 2 3
var B =func.bind(obj)//像call一样的传参方式
B(2,3)//1 2 3
var C =func.bind(obj,2)//像call一样的传参方式
C(3)//1 2 3
//你或许会疑问,为什么可以这样中断了一样传参?
//柯里化形式传参 fn(1)(2),先看下闭包
手动实现bind/原理
参考:另一个优快云博客
Function.prototype.myBind = function () {
var self = this; // 保存原函数
context = [].shift.call(arguments);
// 保存需要绑定的this上下文,取bind函数的第一个参数
// 这里就是重新绑定this 的部分
out_args = [].slice.call(arguments); // 剩余的参数转为数组
return function () { // 【闭包】返回一个新函数
let in_args = [].slice.call(arguments)
self.apply(context,[].concat.call(out_args ,in_args));
//“借用”call首先将内外的参数arguments拼接起来并到一起
//同时也解释了上面ABC三个函数的传参差异导致一样的结果的原因---柯里化形式传参 fn(1)(2)
//新的this主context“借用”原函数
}
}
解释
arguments类数组
类数组不是数组,无法直接使用数组方法,所以需要call
和apply
借到数组对象的方法使用
函数里arguments
表示传入的参数数组,具有length
属性
function fff(){
console.log(arguments)
}
fff(1,2,3,"代码")
[].数组方法
Array.prototype.shift === [].shift //true
//删除并返回数组的第一个元素
闭包传参
function f1(x){
function f2(y){ //f2是一个闭包
console.log(x)
console.log(y)
}
return f2;
}
f1(1)(2)//1 2