apply、call、bind區別、用法

apply和call都是爲了改變某個函數運行時的上下文而存在的(就是爲了 改變函數內部this的指向);
 
若是使用apply或call方法,那麼this指向他們的第一個參數,apply的第二個參數是一個參數數組,call的第二個及其之後的參數都是數組裏面的元素,就是說要所有列舉出來;
 
他們的 經常使用用法
1.數組之間的追加;
2.獲取數組中的最大值和最小值,利用他們擴充做用域擁有Math的min和max方法;
因爲沒有什麼對象調用這個方法,因此第一個參數能夠寫做null或者自己;
var  numbers = [5, 458 , 120 , -215 ]; 
var  maxInNumbers = Math.max.apply(Math, numbers),   //458
       maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458
3.驗證是不是數組(前提是toString()方法沒有被重寫過)
function   isArray(obj){ 
    return Object.prototype.toString.call(obj) === '[object Array]' ;
}
4.讓類數組擁有數組的方法
 
好比arguments對象,獲取到的文檔節點等,並無數組的那些方法:
Array.prototype.slice.apply(argument); //理論上來講這個比較快,直接在原型上查找slice方法
                                                                 //但實際上比較慢
或者
[].slice.apply(arguments); //理論上來講這個比較慢,由於要Array作一個實例化再查找slice方法
                                        //實際上比較快,由於如今的各類自動化工具會把上一種方法轉換爲這種,而第二種代碼比較簡潔,因此會比較快;
 
 
bind()--也是改變函數體內this的指向;
bind會建立一個新函數,稱爲綁定函數,當調用這個函數的時候,綁定函數會以建立它時傳入bind()方法的第一個參數做爲this,傳入bind()方法的第二個及之後的參數加上綁定函數運行時自己的參數按照順序做爲原函數的參數來調用原函數;
 
bind與apply、call最大的區別就是:bind不會當即調用,其餘兩個會當即調用
例子:
 
若是屢次調用bind,那麼多出來的次數都是無效的,
 
 
三個的使用區別:
都是用來改變函數的this對象的指向的;
第一個參數都是this要指向的對象;
均可以利用後續參數傳參;
bind是返回對應函數,便於稍後調用,apply、call是當即調用;
 
 
 

詳解call(),apply()和bind()

http://blog.csdn.net/u014267183/article/details/52610600es6

原創 2016年09月21日 17:32:57

  以前看了點es6的箭頭函數,爲了搞懂箭頭函數的this,看了不少文章,也順便看了幾個綁定函數,發現不少之前沒注意的問題,收穫很多。面試

  以前就在網上的筆試題中看過用js實現bind()函數,沒怎麼在乎,覺得既然都是用來進行上下文綁定的,用call或者apply應該就能實現。如今看,我仍是圖樣圖森破。數組

  先來說一下call()和apply()吧,對於這兩個函數,我是看本身的書學習的,學的時候沒覺的有什麼問題,可是我查了一下網上的關於call()和apply()的文章,尼瑪啊,這說都是些什麼啊!!看着真費勁。瀏覽器

  其實,call()和apply()就是改變函數的執行上下文,也就是this值。他們兩個是Function對象的方法,每一個函數都能調用。他們的第一個參數就是你要指定的執行上下文,第二個用來傳遞參數(說第二個不許確,應該說第二部分,由於參數能夠傳多個),也就是傳給調用call和apply方法的函數的參數。說白了,就是調用函數,可是讓它在你指定的上下文下執行,這樣,函數能夠訪問的做用域就會改變。下面看點代碼:app

function apply1(num1, num2){
    return sum.apply(this, [num1, num2]);
    }
function call1(num1, num2){
    return sum.call(this, num1, num2);函數

    }工具

這裏,咱們執行環境傳的是this,也就是說沒改變函數的執行上下文。這兩段代碼,只是想告訴你call和apply的區別。post

call的第二部分參數要一個一個傳,apply要把這些參數放到數組中。這就是他們的區別,真的就這麼點區別!!!學習

而後,不得不說的一點:它們的第二個參數均可以傳arguments。測試

 

—————————————————————————————————————————————————————————————————————————————

下面來說bind()函數,bind()是es5中的方法,他也是用來實現上下文綁定,看它的函數名就知道。bind()和call與apply不一樣。bind是新建立一個函數,而後把它的上下文綁定到bind()括號中的參數上,而後將它返回。

因此,bind後函數不會執行,而只是返回一個改變了上下文的函數副本,而call和apply是直接執行函數。

下面代碼能夠反映出這點,並且也顯示了bind的用法(後面的代碼皆取自張鑫旭大神的博客)

var button = document.getElementById("button"),
    text = document.getElementById("text");
button.onclick = function() {
    alert(this.id); // 彈出text
}.bind(text);

但因爲ie6~ie8不支持該方法,因此若想在這幾個瀏覽器中使用,咱們就要模擬該方法,這也是面試常考的問題,模擬的代碼以下:

 

if (!function() {}.bind) {
    Function.prototype.bind = function(context) {
        var self = this
            , args = Array.prototype.slice.call(arguments);
            
        return function() {
            return self.apply(context, args.slice(1));    
        }
    };
}
就是這段代碼,糾正了我長久以來的一個誤區。下面來說一下這段代碼

 

首先,咱們判斷是否存在bind方法,而後,若不存在,向Function對象的原型中添加自定義的bind方法。

這裏面var self = this這段代碼讓我很困擾,按理說,prototype是一個對象,對象的this應該指向對象自己,也就是prototype,但真的是這樣嗎。看看下面的代碼:

function a(){};

a.prototype.testThis = function(){console.log(a.prototype == this);};

var b = new a();

b.testThis();//false

顯然,this不指向prototype,而通過測試,它也不指向a,而指向b。因此原型中的this值就明朗了。指向調用它的對象。

 

Array.prototype.slice.call(arguments);
接下來就是上面這段代碼,它會將一個類數組形式的變量轉化爲真正的數組。爲啥呢,其實書上並無說slice還有這樣的用法,也不知道是誰發明的。slice的用法能夠順便上網查一下,就能查到。但要更正一點,網上的介紹說slice有兩個參數,第一個參數不能省略。然而我不知道是我理解的問題仍是咋地,上面這段代碼tmd不就是典型的沒傳參數嗎!!!arguments是傳給call的那個上下文,前面講過,不要弄混(因爲arguments本身沒有slice方法,這裏屬於借用Array原型的slice方法)。並且通過測試,若果你不給slice傳參數,那就等於傳了個0給它,結果就是返回一個和原來數組如出一轍的副本。

這以後的代碼就很好理解,返回一個函數,該函數把傳給bind的第一個參數當作執行上下文,因爲args已是一個數組,排除第一項,將以後的部分做爲第二部分參數傳給apply,前面講過apply的用法。

如此,咱們本身的這個bind函數的行爲就同es5中的bind同樣了。

相關文章
相關標籤/搜索