艾利百科--临沂网站制作,临沂网页设计,临沂微信公众号,兼容并蓄,开放共赢!

艾利百科

当前位置: 主页 > 网站制作 > jQuery/JS >

JS中apply() call() bind()的方法区别与联系

时间:2018-09-22 21:48来源:未知 作者:kunbeatable 点击:
我们都知道 call apply bind 都可以改变函数调用的 this 指向。那么它们三者有什么区别,什么时候该用哪个呢? 为什么需要这些?主要是因为this,来看看this干的好事。 box.onclick = function(){ function fn(){ alert(this); } fn(); }; 1 2 3 4 5 6 我们
我们都知道call apply bind都可以改变函数调用的this指向。那么它们三者有什么区别,什么时候该用哪个呢?

为什么需要这些?主要是因为this。

box.onclick = function(){
  function fn(){
    alert(this);
  }
  fn();
};

我们原本以为这里面的this指向的是box,然而却是Window。一般我们这样解决:

box.onclick = function(){
  var _this = this;
  function fn(){
    alert(_this);
  }
  fn();
};
将this保存下来。

还有一些情况,有时我们想让伪数组也能够调用数组的一些方法,这时call、apply、bind就派上用场了。
我们先来解决第一个问题修复this指向。

box.onclick = function(){
  function fn(){
    alert(this);
  }
  fn();
};
改成如下:
box.onclick = function(){
  function fn(){
    console.log(this);
  }
  fn.call(this);
};

call的作用就是改变this的指向的,第一个传的是一个对象,就是你要借用的那个对象。

fn.call(this);
这里的意思是让this去调用fn这个函数,这里的this是box,box调用fn,这句话非常重要,我们知道this它始终指向一个对象,刚好box就是一个对象。那么fn里面的this就是box。

box.onclick = function(){
  function fn(){
    console.log(this);
  }
  fn.call(this);
};

这句话在某些情况下是可以简写的,比如:

box.onclick = function(){
  var fn = function(){
    console.log(this); //box
  }.call(this);
};

或者这样:

box.onclick = function(){
  (function(){
    console.log(this);
  }.call(this)); //box
};

又或者这样:

var objName = {name:'JS2016'};
var obj = {
  name:'0 _ 0',
  sayHello:function(){
    console.log(this.name);
  }.bind(objName)
};
obj.sayHello();//JS2016

call和apply、bind都是用来改变this的指向的,但也有一些小小的差别。下面我们来看看它们的差别在哪:

function fn(a,b,c,d){
  console.log(a,b,c,d);
}
//call
fn.call(null,1,2,3);
//apply
fn.apply(null,[1,2,3]);
//bind
var f = fn.bind(null,1,2,3);
f(4);

结果如下:
1 2 3 undefined
1 2 3 undefined
1 2 3 4

前面说过第一个参数传的是一个你要借用的对象,但这么我们不需要,所有就传了一个null,当然你也可以传其他的,反正在这里没有用到,除了第一个参数后面的参数将作为实际参数传入到函数中。

call就是挨个传值,apply传一个数组,bind也是挨个传值,但和call和apply还有一些不同,使用call和apply会直接执行这个函数,而bind并不直接执行,而是将绑定好的this重新返回一个新函数,什么时候调用由你自己决定。

var objName = {name:'JS2016'};
var obj = {
  name:'0 _ 0',
  sayHello:function(){
    console.log(this.name);
  }.bind(objName)
};
obj.sayHello();//JS2016

这里也就是为什么我要用bind的原因,如果用call的话就会报错了。自己想想这个sayHello在obj都已经执行完了,就根本没有sayHello这个函数了。

这几个方法使用的好的话可以帮你解决不少问题比如:
正常情况下Math.max只能这样用

Math.max(10,6)

但如果你想传一个数组的话你可以用apply

var arr = [1,2,30,4,5];
console.log(Math.max.apply(null,arr));

又或者你想让伪数组调用数组的方法

function fn(){
  [].push.call(arguments,3);
  console.log(arguments); //[1, 2, 3]
}
fn(1,2);

再者:

var arr = ['aaabc'];
console.log(''.indexOf.call(arr,'b')); //3

实际上浏览器内部根本就不在乎你是谁,它只关心你传给我的是不是我能够运行的,如下:
正常情况

var str = 'aaabc';
console.log(str.indexOf('b'));

而这种情况其实做的事情和上面一模一样,看我来拆解。

var arr = ['aaabc'];
''.indexOf.call(arr);

这句话就是说让arr调用字符串的indexOf方法,前面说过了浏览器内部不在乎你是谁,所以谁都可以来调用,但不是100%成功,具体看如下。

''.indexOf.call(arr,'b')

这里的arr就是[‘aaabc’],内部很可能拆成了’aaabc’,因此就成了下面的这段代码。

'aaabc'.indexOf('b');

总结
当我们使用一个函数需要改变this指向的时候才会用到call`apply`bind
如果你要传递的参数不多,则可以使用fn.call(thisObj, arg1, arg2 ...)
如果你要传递的参数很多,则可以用数组将参数整理好调用fn.apply(thisObj, [arg1, arg2 ...])
如果你想生成一个新的函数长期绑定某个函数给某个对象使用,则可以使用const newFn = fn.bind(thisObj); newFn(arg1, arg2...)

顶一下
(1)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片