JS中的call、apply、bind

weixin_33816946發表於2018-03-29

JS中的call、apply、bind都是用來改變函式中this指向的

box.onclick = function(){
    var name = 1;
  function fn(){
    alert(this.name);
  }
  fn();
      console.log(this.name);
};

alert出來的this.name 會顯示undefined

console.log顯示出來的this.name為1

問題來了,函式裡邊的函式的this不是外層函式的this,而是window。

一般我們解決這個問題會用

var _this = this;

來儲存外層函式的this在內層函式中使用。

但本文將介紹一種更加常用的方法改變this指向。

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

很神奇吧,call的作用就是改變this的指向的,第一個傳的是一個物件,就是你要借用的那個物件。

fn.call(this); 
  這裡的意思是讓this去呼叫fn這個函式,這裡的this是box,這個沒有意見吧?如果這個你不清楚,很可能你是javscript的新朋友。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');

相關文章