持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
简单介绍
call,apply,bind是Function对象原型对象上自带的三个方法,所有的函数都能调用,主要作用:改变函数执行时的上下文,或者改变函数调用时的this指向
call方法
call(thisArg,arg1,arg2.....)
执行调用call方法的函数,改变调用call方法的函数中的this指向 指向call方法的第一个参数
call方法参数
this被改变的指向的对象
- 如果第一个参数是 null或者undefined 则改变this指向window
- 如果是基本包装类型,指向其的包装对象
- 如果是对象类型,则直接指向当前对象
- 后边的参数都是被调用函数的实参,用逗号间隔开
代码示例
var obj = {
name:'obj',
say:function(){
console.log(this);
console.log(this.name);
}
}
//正常调用
obj.say(); // obj对象、boj
var obj1 = {
name:'obj1'
};
//改变this指向 obj.say.call(obj1) obj.say里面的this指向了obj1
obj.say.call(obj1); //ob1对象,boj1
apply方法
apply(thisArg,[arg1,arg2...])apply和call基本一样,区别在于传参不同
apply方法参数
- call给函数传参的时候,是作为call的第二个参数以后所有的参数 逗号隔开
- apply 给函数传参的时候,函数的参数全部放在数组中,作为apply的第二个参数
代码示例
var obj = {
name: 'aaa',
say: function (t,f) {
console.log(t,f); // bbb ccc
console.log(this); // obj1对象
console.log(this.name) // hello
}
}
var obj1 = {
name:'hello'
};
//改变this指向为obj1,通过数组的方式传递参数
obj.say.apply(obj1,['bbb','ccc'])
使用场景
apply和call工作方式相同,不同的地方在于传递给调用函数的参数的形式
- 借用其他函数的方法,让本对象使用
- 让其他的构造函数中的属性变成自己的
代码示例
function Demo(name){
this.name = name;
}
var obj = {sex:'nan',age:18};
Demo.apply(obj,['lucky']); //执行的Demo,demo中的this指向了obj,这个时候就相当于obj.name= lucky 所以执行完成之后对象中有了name属性值为lucky
console.log(obj)
/*
{
"sex": "nan",
"age": 18,
"name": "lucky"
}*/
bind方法
和call的功能基本类似,传参方式也一样
区别
- call和apply作用是改变this指向,并直接调用函数
- bind作用是改变this指向,并返回一个改变this指向以后的函数(不会调用)
代码示例
因为我们知道setTimeout里面直接调用this,this的指向会直接指向window,只能在函数内部去定义var that = this的方式去拿到当前函数的this,但是我们通过bind方法能直接实现,但call和apply就不能,这也是bind自己的固有属性决定的。
document.onclick = function () {
//bind绑定与var that = this 同理
setTimeout((function () {
console.log(this) //document
}).bind(this), 100)
}
关于call的面试题
看代码,试着输出一下你的答案
function fn1() {
console.log(1)
}
function fn2() {
console.log(2)
}
fn1.call(fn2);
fn1.call.call(fn2);
打印结果fn1.call(fn2)的输出为1,fn1.call.call(fn2)输出的结果为2
分析
首先call内部里面是这样运行的
Function.prototype.call = function (context,...arg){
//是否有参数,无则指向windon
context = context? Object(context) : window;
//1.改变this指向
context.fn = this;
//2.调用函数
rturn context.fn(...args);
}
fn1.call(fn2)
改变fn1指向为fn2,实际上就是给fn2对象上添加函数fn1,然后执行fn1()
fn1.call.call(fn2)
运行了两次call,可以理解为fn1.call和call(fn2),fn1.call其实就是Functiuon。prototype.call实际上什么都没操作,而call(fn2)则改变了this指向,组合起来就是fn2.call(),但是没有传参所以默认指向window,就是默认调用fn2输出2.所以就算是fn1.call.call.call...(fn2)依旧会输出2。
好了,以上就是本篇文章的分享,感谢阅读!