DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> JavaScript基礎知識 >> call,apply,bind使用異同
call,apply,bind使用異同
編輯:JavaScript基礎知識     
一、call&apply

call, apply都屬於Function.prototype的方法,因為屬於Function.prototype,所以每個Function對象實例,也就是每個方法都有call, apply屬性啦。

如果不明白,請見“Javascript之一切皆為對象3”。

而且它們的作用都是一樣的,只是使用方式不同而已。

作用:借用別人的方法來調用,就像自己有這個方法一樣。

咦,那它們怎樣才能達到這目的呢?

對象。

對象?

是的,其實就是改變執行上下文對象的內部指針,因為在Javascript中,代碼總有一個執行上下文對象,那麼當我手動改變它時,就可以改變這個執行上下文啦,也就可以利用非自己的方法成為自己的方法哦。

我們一起來寫個Demo。

假如,我有一個方法a,它的作用是輸出對象的名字this.name;那麼當我使用call或者apply改變它的執行上下文對象時,它的輸出結果是不一樣的。

什麼意思?

詳情請見下代碼:

<!DOCTYPE html>
    <head>
        <title>call&apply</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
       <script>
           var name = 'windowName';
           //方法a的作用,是輸出對象的名字
           function a(){
               console.log(this.name);
           }
           function b(){
               this.name = 'bName';
           }
           //將a方法的執行上下文對象指向window
           a.call(window);
           //將a方法的執行上下文對象指向new b()
           a.call(new b());
       </script>
    </body>
</html>

執行上述代碼,結果如下:

看見了麼?所以說call,apply的作用就是借用別人的方法,改變別人方法的執行上下文對象為自己,成為自己的方法,為己所用。

注意: call或apply的第一個參數傳的是什麼,它們就會將其默認為執行上下文對象。倘若我們沒有指明call或apply的執行上下文對象,即,call和apply的第一個參數是null、undefined或為空時,在非嚴格模式下,函數內的this指向window或global,浏覽器就是window。嚴格模式下,null為null,undefined或空為undefined。

什麼意思,請見下面的demo(僅以call舉例且為非嚴格模式):

<!DOCTYPE html>
    <head>
        <title>call&apply</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
       <script>
           function print(){
               console.log(this);
           };
           //將第一個參數數字1,作為執行上下文對象
           print.call(0,1,2);
           //將第一個參數字符串'123',作為執行上下文對象
           print.call('123');
           //將第一個參數true,作為第執行上下文對象
           print.call(true);
           //將第一個參數對象,作為執行上下文對象
           print.call(new Object());
           //將null傳入
           print.call(null);
           //將undefined傳入
           print.call(undefined);
           //不傳任何參數
           print.call();
       </script>
    </body>
</html>

看見了麼,我上面傳入的依次是數字,字符串,true,對象,null,undefined和空,得到下面的結果:

 

那麼,call與apply既然作用一樣,那它們有什麼區別呢?

它們的第一個參數,毋庸置疑,都是傳入的執行上下文對象,區別是從第二個參數開始的。call方法的其它參數依次傳遞給借用的方法作參數,而apply就兩個參數,第二個參數為一個數組傳遞。

簡單點,就是:

  fun.call(obj, arg1, arg2…) === fun.apply(obj, [arg1, arg2…]) ===  obj.fun(arg1, arg2…);

咦,call和apply的區別是,參數的傳遞不同,有什麼用呢?

根據它們傳遞參數的區別,當參數明確的時候,使用call;當傳遞的參數不明確時,用 apply咯,即傳遞arguments給apply作為第二個參數。

好了,光說不做沒用,我們寫個demo看看。

<!DOCTYPE html>
    <head>
        <title>call&apply</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
       <script>
           function print(name, age, time){
               console.log("name: "+ name +"  age: "+ age +"  time: "+ time );
           };
           function fn(a, b, c){
               //使用call,參數明確
               print.call(this,a);
               //使用apply,參數明確
               print.apply(this,[a, b]);
               //使用apply,參數不明確
               print.apply(this,arguments);
           }
           fn('monkey',24,'1992');
       </script>
    </body>
</html>

執行上述代碼,結果如下:

call與apply,這下明白了麼?

二、bind

bind,最開始認識它的時候,理解就是改變執行上下文的對象。

比如,當我們使用setTimeout時,默認匿名函數裡的this指向的是window,但使用對象的方法時,我想將this指向對象呢,怎麼辦呢?其中的一個方法就是使用bind。

(關於setTimeout的理解,見“setTimeout那些事兒”)。

如:

<!DOCTYPE html>
    <head>
        <title>bind</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
       <script>
           var name = 'window';
           var obj = {
               name:'monkey',
               print: function(){
                   //在這裡使用bind,顯示地將this指向obj,所以console.log會輸出'monkey'
                   setTimeout(function(){
                       console.log(this.name);
                   }.bind(this),100);
               }
           };
           obj.print();
       </script>
    </body>
</html>

執行上述代碼結果為:

 

好了,既然談到bind是改變執行上下文中的對象,我靠,那我們怎麼不使用call或apply呢?

call或apply不也是改變執行上下文的對象麼?

是的,我們將上面的demo修改下,將bind換成call,代碼如下:

<!DOCTYPE html>
    <head>
        <title>bind</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
       <script>
           var name = 'window';
           var obj = {
               name:'monkey',
               print: function(){
                   setTimeout(function(){
                       console.log(this.name);
                   }.call(this)/*在這裡將bind換成call*/,100);
               }
           };
           obj.print();
       </script>
    </body>
</html>

打開chrome調試器,得下結果:

咦,我靠,這不是和bind一樣麼?

是的,但如果我們將setTimeout的延遲時間,換成2秒,或者更長呢?打開chrome調試器,運行修改後的代碼,你就會發現區別,call或apply是立馬呈現’monkey’,而bind是在延遲相應時間後,呈現’monkey’。

Why?

因為call或apply是將執行上下文對象換了後,立即執行;而bind是將執行上下文對象換了後,創建一個新函數。

我們再一起寫個demo看看。

<!DOCTYPE html>
    <head>
        <title>bind</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
       <script>
           function fun(){
               console.log(this.name);
           }
           function obj1(){
               this.name = 'call||apply';
           }
           function obj2(){
               this.name = 'bind';
           }
           var o1 = new obj1();
           var o2 = new obj2();
           fun.call(o1);
           fun.bind(o2);
       </script>
    </body>
</html>

執行上述代碼,結果為:

 

咦,怎麼只打印了一個’call||apply’呢?

因為我們在上面的代碼中,bind我只是綁定了對象o2,但是它又不立即執行,而是返回一個新函數哦。

我們修改以上代碼,手動執行bind返回後的新函數看看。

<!DOCTYPE html>
    <head>
        <title>bind</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
       <script>
           function fun(){
               console.log(this.name);
           }
           function obj1(){
               this.name = 'call||apply';
           }
           function obj2(){
               this.name = 'bind';
           }
           var o1 = new obj1();
           var o2 = new obj2();
           fun.call(o1);
           //手動調用bind創建的新函數
           fun.bind(o2)();
       </script>
    </body>
</html>

運行代碼:

嘿嘿,這下對了吧。

所以,一定要記住bind方法會創建一個新函數,稱為綁定函數,當調用這個綁定函數時,綁定函數會以創建它時傳入的第一個參數作為this,即執行上下文對象。

好了,晚安everyone~

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved