call、apply、bind
1、相同也不同
我们先从浅显的部分开始讲,
- 这三个方法都可以改变this的指向,都可以进行传参,第一个参数都是修改this的指向
- call() 和 apply() 改变this指向后会立即执行函数
- bind() 改变this指向后不会立即执行
- call() 和 apply() 区别在于参数
· call() 第一个参数是修改的this指向,后续的参数都是传入该函数的值,他的传值只能一个个传
· apply() 第一个参数是修改的this指向,第二个参数是一个数组,所有传入该函数的值都放到该数组中
javaScript权威指南上的解释是:
call() 、apply()可以看作是某个对象的方法,
通过调用方法的形式来间接调用函数。
bind() 就是将某个函数绑定到某个对象上。
2、照常举🌰
var boy = { name : "李雷", gender : "男", age : 17, say : function() { alert(this.name + " , " + this.gender + " ,今年" + this.age); } } var girl = { name : "韩梅梅", gender : "女", age : 16 } boy.say();
此时弹出的内容是:
李雷,男,今年17
那么如果我们想输出girl这个对象的数据怎么办,
换种说法就是,
在只改变这个代码最后一句话的情况下怎么让girl对象拥有say这个方法?
//对于call boy.say.call(girl); //对于apply boy.say.apply(girl); //对于bind boy.say.bind(girl)();
由此可以看出:
call() 和 apply() 改变this指向后会立即执行函数,
bind方法返回的仍然是一个函数需要调用才会执行
此时我们把🌰换成需要传递参数的:
var boy = { name : "李雷", gender : "男", age : 17, say : function(mes1,mes2) { alert(this.name + " , " + mes1 + mes2); } } var girl = { name : "韩梅梅", gender : "女", age : 16 } boy.say("喜欢","韩梅梅"); //此时输出:李雷,喜欢韩梅梅 //call boy.say.call(girl,"也喜欢","自己") //apply boy.say.apply(girl,["也喜欢","自己"]) //bind boy.say.bind(girl,"也喜欢","自己")()
3、如何自己写一个call方法呢?
思路:call方法的思路是改变this的指向,让新的对象可以执行该函数,
那么思路是否可以变为给新的对象添加一个函数,
执行后再删除呢?
//自定义一个myCall方法挂载到Function通过prototype实现公共方法 Function.prototype.myCall = function (context) { //context是obj2,因为只获取了第一个参数 //与call方法一样,context中第一个为新的this的指向 //剩下的部分为传入的参数 //此处是如果没传this指向的话就指向window var context = context || window //此处的this指向调用myCall的函数,就是你定义的初始对象的函数 //此处对应的this就是obj1.fn context.fn = this //获取除了this指向其余的参数 var args = [...arguments].slice(1) //指向函数并把参数传进去 var result = context.fn(...args) //删除该方法 delete context.fn return result } var obj1 = { name:'name1', fn:function(mes){ console.log(this.name+mes) } } var obj2 = { name:"name2" } obj1.fn.myCall(obj2,"111") //输出name2111
4、如何自己写一个apply方法呢?
//整体与call没什么太大的区别 //那我们就主要看看区别 //区别就在于是否需要传参 //因为他的参数全都在数组里 Function.prototype.myApply = function (context) { var context = context || window context.fn = this var result // 需要判断是否存储第二个参数 // 如果存在,就将第二个参数展开 if (arguments[1]) { result = context.fn(...arguments[1]) } else { result = context.fn() } delete context.fn return result }
5、如何自己写一个bind方法呢?
Function.prototype.myBind = function (context) { var _this = this var args = [...arguments].slice(1) // 返回一个函数 return function () { return _this.apply(context, args.concat(...arguments)) } }
以上。