call/apply/bind作用和区别

答案:

他们都可以改变函数的作用域。

  • call/apply 可以直接执行该函数,而 bind 不会立刻执行

fucntion.bind(thisArg, arg1, arg2, ...)
  • call/apply 作用类似,都可以改变指针和执行函数,区别在于传参不同,call 需要单个传参,apply 通过数组传参

function.call(thisArg, arg1, arg2, ...)
function.apply(thisArg, [arg1, arg2, ...])

 

详细解析:

this代表函数(方法)执行的上下文环境,但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。

  • 1.在方法中,this 表示该方法所属的对象。
  • 2.如果单独使用,this 表示全局对象。
  • 3.在函数中,this 表示全局对象。
  • 4.在函数中,在严格模式下,this 是未定义的(undefined)。
  • 5.在事件中,this 表示接收事件的元素。
  • 6.类似 call() 和 apply() 方法可以将 this 引用到任何对象。

JavaScript 提供了call、apply、bind这三个方法,来切换/固定this的指向。

call和apply

call 和 aplly 作用完全一样,都是在特定的上下文中调用函数,或者说改变函数内部的this指向;区别仅在于接收参数的方式不同。

function add(a, b) {
  return a + b;
}
 
function sub(a, b) {
  return a - b;
}
 
console.log(add.call(sub, 2, 1));//3

为什么add.call(sub, 2, 1)的执行结果是3呢,因为call()方法改变了this的指向,使得sub可以调用add的方法,也就是用sub去执行add中的内容。

var dog = {
  name: "dog"
};
var cat = {
  name: "cat"
};
var sayName = function (age, gender) {
  console.log(this.name + "," + age + "," + gender)
};
sayName(); //undefined
sayName.call(dog, 2, "male"); //dog,2,male
sayName.call(cat, 3, "female"); //cat,3,female
sayName.apply(dog, [2, "male"]); //dog,2,male
sayName.apply(cat, [3, "female"]); //cat,3,female

我们在全局环境定义了一个 sayName 方法,调用该方法时会将当前环境的 name 属性 (this.name) 显示到控制台上。当我们在全局环境调用 sayName() 时,由于全局环境并没有 this.name 属性,因此显示了 undefined。

使用 call 或者 apply,就可以改变函数的执行环境,或者说改变函数内部的 this 指向。例如 sayName.call(dog),表示将sayName 内部的 this 指向了 dog 对象,因此 this.name 显示为 "dog"。当我们调用sayName.call(cat)时,sayName 内部的 this 又指向了 cat 对象。总结一句话就是call()可以让括号里的对象来继承括号外函数的属性。

可以看出来,call与apply的作用完全相同,区别仅在于接收参数的方式不同。

fn.call(context, arg1, arg2, ...)
fn.apply(context, [arg1, arg2, ...])

call 和 apply 接收的第一个参数都是函数的运行环境。使用 call 时传递给函数的参数必须逐个传入,而使用 apply 时函数的参数应该是一个数组,或者类数组对象(如 arguments 对象)。至于使用 call 还是 apply,完全取决于采用哪种方法给函数传递参数更方便。在不需要给函数传递参数的情况下,使用哪个方法都无所谓。

apply的2种写法:

People.apply(this, [name, age]);
People.apply(this, arguments);

在这里arguments和[name, age]是等价的。

 

bind

bind 与前两者作用类似,都是改变函数内部的 this 指向,区别在于 bind 会创建一个新的函数实例,每次调用该实例时,都会在被绑定的环境中运行。简单来说就是,bind方法返回一个新函数,以后调用了才会执行,但apply、call会立即执行。

function f(y, z){
  return this.x + y + z;
}
var m = f.bind({x : 1}, 2);
console.log(m(3));
//6

这里bind方法会把它的第一个实参绑定给f函数体内的this,所以这里的this即指向{x : 1}对象,从第二个参数起,会依次传递给原始函数,这里的第二个参数2,即是f函数的y参数,最后调用m(3)的时候,这里的3便是最后一个参数z了,所以执行结果为1 + 2 + 3 = 6分步处理参数的过程其实是一个典型的函数柯里化的过程(Curry)。

var dog = {
  name: "dog"
};
var cat = {
  name: "cat"
};
var sayName = (function (age, gender) {
  console.log(this.name + "," + age + "," + gender)
}).bind(dog, 3, "male");
sayName.call(cat, 2, "female"); //dog,3,male

我们创建 sayName 函数时,使用 bind 将该函数的 this 指向了 dog 对象,同时还绑定了传入函数的参数。

现在我们调用 sayName.call(cat, 2, "female"),发现不论是this对象,还是传入函数的参数,都是之前被绑定的值了。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值