刚好最近在弄函数的防抖节流的问题,注意到了 apply、call和bind,就了解了一下,所以顺便记录一下。因为是自己的了解,不能保证正确,谢谢了!
注意点
首先要确定的是,
-
这三者都用于改变函数 this 的指向。
-
这三者的第一个参数都是 this 想要指向的对象,注意是想要指向的对象,而不是原对象,如果没有这个参数,或者这个参数为 undefined 或者 null 时,则指向全局 window。
-
三者都可以传参,但是
- apply 传递的参数是数组
- call 传递的是参数列表
- apply 和 call属于一次性传入参数,bind 可以分为多次传入参数
- 返回略有不同
- bind 返回绑定 this 之后的函数,便于后面调用
- apply 和 call 则是立即执行
- 如果 bind() 返回的新函数作为构造函数创建了一个新的对象,那么此时 this 不再指向传入给 bind 的第一个参数,即这个构造函数,而是指向这个构造函数所创建的实例
例子
var name = '小王',
age = 17;
var obj = {
name: '小张',
objAge: this.age,
myFun:function(fm, t){
return (
"姓名:" + this.name + ", 年龄:" +this.age + ", 来自:" + fm + ", 去往:" + t
);
}
}
console.log(obj.objAge) // 17
console.log(obj.myFun()) // 姓名:小张,年龄:undefined
// 从这里可以看出,此时 obj 的 this 指向 window 而 函数 myFun 的this 指向的是 obj
var fav = '可达鸭';
function shows(){
return (this.fav)
}
console.log(shows()) // 可达鸭
// 比较这两者 this 的区别,第一个打印的 this 指向 obj,第二个全局声明的 shows() 函数 this 指向 window
// 当定义下面的时候 上面 obj.myFun() 的打印会发生变化,涉及到函数深浅拷贝的问题
var db = {
name: '五花肉',
age: 108
};
console.log(obj.myFun.call(db, "成都", "上海")); // 姓名:五花肉,年龄:108,来自:成都,去往:上海
console.log(obj.myFun.call(db, ["成都", "上海"])); // 姓名:五花肉,年龄:108,来自:成都,上海,去往:undefined
// console.log(obj.myFun.apply(db,"成都", "上海")); // 会报错
console.log(obj.myFun.apply(db, ["成都", "上海"])); // 姓名:五花肉,年龄:108,来自:成都,去往:上海
console.log(obj.myFun.bind(db, "成都", "上海")()); // 姓名:五花肉,年龄:108,来自:成都,去往:上海
console.log(obj.myFun.bind(db, ["成都", "上海"])()); // 姓名:五花肉,年龄:108,来自:成都,上海,去往:undefined
上面的结果不难看出:
-
- call、bind 和 apply 这三个函数的第一个参数都是 this 的指向对象,差别在于第二个参数:
-
- call 的参数是直接放进去的,第二个第三个直至第 N 个参数都是用逗号进行分隔。直接放在后面 obj.myfun.call(db, "成都", ..., "string").
-
- apply 的所有参数必须放在一个数组内部传递进去 obj.myFun.apply(db,["成都", ..., "string"])。
-
- bind 除了返回的是函数以外,他的参数和 call 一致
-
- 上面三种改变 this 指向的方法,除了 bind 后面多了一个 () 之外,前面的姓名和年龄,结果返回都是一致的 由此得出结论,bind 返回的是一个新的函数,你必须调用它才会执行