call、apply、bind方法的作用
首先这几个方法的作用都是改变this用的,他们都是函数身上的方法,所以可以通过函数点方法的方式去调用
区别:
传参方式:
call跟bind的传参方式是一样的,都是第一个参数为对象(需要指向那个对象),后面接其他任意数量的参数
而apply的传参方式略有不同,第一个参数依然还是需要指向的那个this对象,然后第二个参数是一个数组,只能接收两个参数
执行方式:
call跟apply都是直接函数点方法直接调用,而bind不一样,他不会直接调用,他会返回一个新的函数,然后你需要再次调用这个新的函数才会执行
function fun(a, b) {
console.log(this.name, '当前this');
console.log(a, b, '其余参数');
}
//
fun.call({
name: '球'
}, '篮球', '足球');
fun.apply({
name: '球'
}, ['篮球', '足球']);
const newFun = fun.bind({
name: '球'
}, '篮球', '足球');
newFun();
手写call:
主要思路是往函数原型上添加一个方法,然后再方法内部利用对象添加属性的方式来改变this
// 定义一个函数
function fun(a, b) {
console.log(this.name, '当前this');
console.log(a, b, '其余参数');
}
// call方法的作用就是改变this,把函数的this变成传入的第一个参数对象,然后后面可以接任意数量的参数
fun.call({
name: 'call'
}, '篮球', '足球');
// 因为call是函数的方法,所以依照原型链往函数的原型上添加方法,这里我添加一个mycall方法,名字随便取
Function.prototype.mycall = function mycall(context,...par){
// call方法的第一个参数为对象,所以这里我们第一个参数不能跟后面的...参数写反,...可以理解为将一堆参数依次展开
console.log(this);//通过打印我们可以看出这里的this指向是调用mycall的那个函数
let that = Symbol('that')//定义一个symbol,由于传进来的对象可能存在与你添加的属性同名的情况,所以这里利用下symbol
//所以这里我们可以通过对象.的方式(也就是添加一个属性)来改变this,刚好我们这里有个对象参数context,
//往他身上添加一个that属性让他等于当前this(调用mycall的函数),this指向就变成了context(传入的对象)
context[that] = this
// 然后that呢刚好又是那个调mycall的函数,所以我们直接调用他,把剩余的参数传给他
context[that](...par);//这里调that方法相当于直接调外面的fun函数,所以直接把剩余参数同普通函数传参一样传进去就行了
delete context[that]//由于这个context对象原本是没有that属性的,所以用完之后我们得删除了 不能搞乱了别人原本的对象
}
fun.mycall({name:'参数this'},'参数一','参数二');//调用自己手写的mycall方法试试
手写apply:
主要思路是往函数原型上添加一个方法,然后再方法内部利用对象添加属性的方式来改变this
// 定义一个函数
function fun(a, b) {
console.log(this.name, '当前this');
console.log(a, b, '其余参数');
}
fun.apply({
name: '球'
}, ['篮球', '足球']);
Function.prototype.myapply = function myapply(context,arr){
const type = Array.isArray(arr)//判断一下第二个参数是否为数组
if(arr && !type){
// 存在第二个参数且第二个参数不是数组的情况下抛出错误
throw new Error(`${arr}is not 'array'`)
}
let only = Symbol('that')//定义一个唯一值symbol,symbol名为that
context[only] = this//改变this指向,使当前this(调用myapply时的函数)指向context
context[only](arr);//执行下函数
delete context[Symbol('that')]//删除自己添加的那个属性
}
fun.myapply({
name: 'myapply球'
},['wewe','dfdfdf'])
手写bind:
主要思路是往函数原型上添加一个方法,然后再方法内部利用对象添加属性的方式来改变this,然后返回一个函数
// 定义一个函数
function fun(a, b, c) {
console.log(this.name, '当前this');
console.log(a, b, c, '其余参数');
}
//
const bindFun = fun.bind({
name: '参数name1'
}, ['篮球', '足球']);
Function.prototype.myBind = function (context, ...params) {
// 手写bind的主要区别就是返回一个函数
//如果是下面这种写法,步骤都写在返回的函数里面那返回的函数必须得是箭头函数,
// 因为箭头函数没有自己的this,没有他就会往外面找,如果是普通函数,因为外面调用这个函数的时候是在window下,所以this指向window
return (...params2) => {
let taht = Symbol('that')
context[taht] = this//箭头函数下这个赋值可以写在返回函数里面,如果是普通匿名函数就得写返回函数的外面了
context[taht](...params, ...params2);//可以对参数进行一个拼接,使其二次调用时可以再次传参
delete context[taht]
}
}
const myBindFun = fun.myBind({
name: '参数name'
}, 'sdsdd', 'zzzzz')
myBindFun('weew');//再次调用时才会执行