1. 程式人生 > >JS——call()和apply()的用法

JS——call()和apply()的用法

在上一篇文章中我們對js中的this指向問題進行了介紹,其中涉及到call()和apply()方法,在這篇文章中,我們將對call()和apply()進行探討;

首先我們來說說這兩種方法的共同點:

1. 每個函式都包含兩個非繼承而來的方法:call()方法和apply()方法。

2.這兩個方法的作用是一樣的。 都是在特定的作用域中呼叫函式,等於設定函式體內this物件的值,以擴充函式賴以執行的作用域。

在JS中this總是用來指向某個方法的物件,而call()和apply()的作用就是用來改變this的指向

call()和apply()作用完全一樣,只是接受引數的方式不一樣。

call的用法:

下面的程式碼演示了this指向問題,call()改變this指向,以及call()實現繼承

//下面這段程式碼主要演示了this指向的問題

    window.color = 'red';
    document.color = 'yellow';
    var s1 = {color: 'blue' };

    changeColor(){
        console.log(this.color);
    }


    changeColor.call();         //red (預設傳遞引數)
    changeColor.call(window);   //red
    changeColor.call(document); //yellow
    changeColor.call(this);     //red
    changeColor.call(s1);       //blue



//下面我們將看看call是怎樣改變this指向的

    var Pet = {
         words : '...',
         speak : function (say) {
              console.log(say + ''+ this.words)
         }
    }

    Pet.speak('Speak'); // 結果為:Speak...

    var Dog = {
         words:'Wang'
    }       //將this的指向改變成了Dog

    Pet.speak.call(Dog, 'Speak'); //結果為: SpeakWang



//下面這段程式碼我們再看看使用call()實現繼承

  function Animal(name){   
        this.name = name;   
        this.showName = function(){   
             console.log(this.name);   
        }   
  }   
 
  function Cat(name){  
         Animal.call(this, name);  
  }   
 
  var cat = new Cat("Black Cat");   
  cat.showName();     //結果為:  Black Cat

apply()與call()用法類似,可參考上面的例子

下面我們看看不同點,即傳入引數不同:

var func = function(arg1, arg2) {
     
};

//呼叫該函式的兩種不同方式
func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])

其中 this 是你想指定的上下文,他可以是任何一個 JavaScript 物件(JavaScript 中一切皆物件),call 需要把引數按順序傳遞進去,而 apply 則是把引數放在數組裡。

我們已經看了call()和apply()的基本用法,下面我們用一些例項鞏固一下:

1.陣列的追加

var array1 = [1,2,3]; 
var array2 = [a,b,c]; 
Array.prototype.push.apply(array1, array2); 
// array1 值為  [1,2,3,a,b,c] 

Array.prototype.push可以實現陣列的追加

2.獲取陣列中的最大最小值

var  numbers = [5, 458 , 120 , -215 ]; 
var maxInNumbers = Math.max.apply(Math, numbers),   //458
    maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458

number 本身沒有 max 方法,但是 Math 有,我們就可以藉助 call 或者 apply 使用其方法。

3.驗證是否為資料型別

console.log(Object.prototype.toString.call(123)) //[object Number]
console.log(Object.prototype.toString.call('123')) //[object String]
console.log(Object.prototype.toString.call(undefined)) //[object Undefined]
console.log(Object.prototype.toString.call(true)) //[object Boolean]
console.log(Object.prototype.toString.call({})) //[object Object]
console.log(Object.prototype.toString.call([])) //[object Array]
console.log(Object.prototype.toString.call(function(){})) //[object Function]

4.類陣列使用陣列方法

首先我們要明白什麼是類陣列:

1.具有length屬性

2.按索引方式儲存資料

3.不具有陣列的push,pop等方法

常見的類陣列有:arguments,NodeList

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


Array.prototype.slice.call(document.getElementsByTagName("*"));

Javascript中存在一種名為偽陣列的物件結構。比較特別的是 arguments 物件,還有像呼叫 getElementsByTagName , document.childNodes 之類的,它們返回NodeList物件都屬於偽陣列。不能應用 Array下的 push , pop 等方法。 但是我們能通過 Array.prototype.slice.call 轉換為真正的陣列的帶有 length 屬性的物件,這樣 domNodes 就可以應用 Array 下的所有方法了。

下面是一個經典的面試題:

定義一個 log 方法,讓它可以代理 console.log 方法,常見的解決方法是:

1:

function log(msg) {
  console.log(msg);
}
log(1);    //1
log(1,2);    //1

2:上面方法可以解決最基本的需求,但是當傳入引數的個數是不確定的時候,上面的方法就失效了,這個時候就可以考慮使用 apply 或者 call,注意這裡傳入多少個引數是不確定的,所以使用apply是最好的,方法如下:

function log(){
  console.log.apply(console, arguments);
};
log(1);    //1
log(1,2);    //1 2

3.接下來的要求是給每一個 log 訊息新增一個"(app)"的前輟,比如:

log("hello world"); //(app)hello world

該怎麼做比較優雅呢?這個時候需要想到arguments引數是個偽陣列,通過 Array.prototype.slice.call 轉化為標準陣列,再使用陣列方法unshift,像這樣:

function log(){
  var args = Array.prototype.slice.call(arguments);
  args.unshift('(app)');
 
  console.log.apply(console, args);
};

log('hello world')      //(app)hello world

以上是關於apply()和call()的一些用法,不盡詳細,歡迎指正