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/52610600

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

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

  之前就在網上的筆試題中看過用js實現bind()函數,沒怎么在意,以為既然都是用來進行上下文綁定的,用call或者apply應該就能實現。現在看,我還是圖樣圖森破。

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

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

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

    }

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

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一樣了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM