call、apply、bind函數詳解

 咱們都知道call,apply,bind函數都是爲了改變this的指向,那麼對於三種函數有什麼相同點有什麼不太點或者有什麼應用呢?下面咱們來進行介紹javascript

call與apply函數

 在javascript種,call,apply的出現是爲了改變函數體內部this的指向,下面咱們來看一個栗子,並從中進行分析。java

var a = "我是window的小a";
       var obj = {
           a:"我是obj的小a",
           foo:function (...arg) {
               console.log(this.a,this,...arg)
           }
       }

       obj.foo()    //此時的this爲obj

       var f2 = obj.foo
       f2()     //此時的this爲window

       f2.call(obj,1,2,3)  //call改變了this的指向,此時的this爲obj,並傳入參數    
       f2.call(obj,[1,2,3]) //輸出obj中的a
       f2.apply(obj,[1,2,3],3,4,5) //apply改變了this的指向爲obj,傳入參數數組,在參數數組以後傳遞參數,並不能傳入該參數
       f2.apply(obj,1,2,3)  //報錯!apply第二個參數必須爲參數數組

咱們來看一下輸出結果。
在這裏插入圖片描述
 由上述輸出結果來看,使用call和apply可以改變this的指向。函數f2本來的指向爲window,使用call和apply函數綁定obj後this的指向爲obj。對於上述的輸出結果還有一個報錯?立馬不淡定了。原來apply的第二個參數只能傳入參數數組,不能傳入多個參數。數組

對於上述輸出結果的小總結爲:app

  • call和apply都用於去改變this的指向問題,第一個參數爲this所指向的對象
  • call和apply都爲直接調用函數,返回值就爲調用函數的返回值。
  • call的第二個位置和以後傳遞參數列表,當向call中傳遞數組時,則視爲只傳遞了一個參數(這個參數爲數組)
  • apply的第二個位置只能傳遞參數數組,在參數數組以後傳遞參數,均失效。

根據call和apply的特色,咱們能夠有如下應用。函數

使用call進行繼承

function father(name,age,hometown,hobby) {
            this.name = name;
            this.age = age;
            this.hometown = "中國"
            this.hobby = hobby;
        }
        function son(name,age,hobby,hometown) {
            father.call(this,name,age,hometown)//繼承父類中的多個屬性
            this.hobby = hobby;
        }
        
        let f = new father("小頭爸爸",38,"中國","釣魚");
        let s = new son("大頭兒子",16,"打球");
        
        console.log(f)
        console.log(s)

輸出結果:
在這裏插入圖片描述this

使用call判斷數據類型

console.log(Object.prototype.toString.call("pp"))
        console.log(Object.prototype.toString.call({age:15}))
        console.log(Object.prototype.toString.call(23))
        console.log(Object.prototype.toString.call([1,2,3]))

在這裏插入圖片描述
 在這我就不一一列舉關於數據的數據類型了,此時確定有人產生疑惑,爲何平時咱們用的obj.toString和object.prototype.toString.call(obj)的結果爲何不同了呢?由於咱們使用的obj.toString()在一些數據類型中都重寫了toString的方法,對於函數和數組來說,使用obj.toString都會直接輸出字符串,故使用obj.toString()不能輸出數據類型。但爲何Object.prototype.toString.call(obj)可以輸出數據類型的值呢?由於toString爲Object的原型方法,並無像obj.toString()同樣重寫該方法。使用Object上的原型中的toString方法的返回值爲數據類型。故咱們能夠經過Object.prototype.toString.call(obj)來判斷數據類型。spa

使用call使僞數組使用數組方法

<div class="xixi"></div>
    <div class="xixi"></div>
    <div class="xixi"></div>
    <div class="xixi"></div>
    <script>
        //將僞數組轉換爲數組,使其能夠調用數組所具備的方法
        var realArr = Array.prototype.slice.call(document.getElementsByTagName("div"));
        realArr.push(1)
        console.log(realArr)
        //僞數組
        var div = document.getElementsByTagName("div")
        div.push(1)  //報錯爲僞數組中沒有數組具備的方法
    </script>

輸入結果:
在這裏插入圖片描述prototype

 對於咱們調用的一些方法例如document.getElementsByName()、document.getElementsByTagName() ,childNodes/children 等返回的均爲僞數組,此時不能使用數組的方法,咱們可使用call函數使其轉換爲真正數組所帶有真正數組方法的對象,這個時候咱們就可以調用數組的全部方法啦。code

使用apply進行數組的鏈接

var arr1 = [1,"xixi",{age:17},34]
        var arr2 = [3,"haha",{age:44},21]
        Array.prototype.push.apply(arr1,arr2)//進行數組的鏈接
        console.log(arr1)

在這裏插入圖片描述

使用apply獲取數組中的最大值

var arr1 = [1,3,4,5,93]
        //實際爲向Math.max中傳入參數arr1,等同於Math.max(arr1)
        var max = Math.max.apply(Math.max,arr1)
        console.log(max)

bind函數

 與call和apply類似,其做用都是用於改變函數內部this的指向。但第二個參數開始是傳入參數列表,這點與call類似,但與其有什麼不一樣的地方呢?call與apply是當即執行函數而bind函數是將函數返回。對象

綁定函數

使用bind方法會返回一個函數,使其函數不管怎麼調用,其this都會指向原來所綁定的那個對象

var a = "我是window的小a";
       var obj = {
           a:"我是obj的小a",
           foo:function (...arg) {
               console.log(this.a,this,...arg)
           }
       }

       obj.foo()    //此時的this爲obj

       var f1 = obj.foo()  //此時的this爲window

       var f2 = f1.bind(obj)  //綁定this爲obj,並返回一個新函數
       f2() //輸出我是obj的小a

配合使用setTimeout

在咱們沒有給setTimeout綁定this的狀況下,當咱們在setTimeout中使用this,this關鍵字會指向window對象,咱們能夠利用bind函數綁定this,使其可以利用this調用想要綁定的函數。

function foo() {
        this.age = 20
    }
    //函數f1
    foo.prototype.f1 = function () {
        console.log(this)   //此時的this爲foo
        setTimeout(this.f2,1000) //可是此時的this爲window,而不是foo,所以沒法調用f2
        var _this = this   //獲取到當前的this
        setTimeout(this.f2.bind(_this),1000) //將this.f2的this綁定給foo
    }
    //函數f2
    foo.prototype.f2 = function () {
        console.log("個人年齡爲:" + this.age)
    }
    var foo = new foo()  //創造實例
    foo.f1()

使用bind將類數組轉換爲數組

function foo() {

        var TempSlice = Array.prototype.slice;
        // 把函數的call方法綁定在數組slice方法上,以後再給call方法傳遞參數
        var slice = Function.prototype.call.bind(TempSlice);
        return slice(arguments);

    }
    console.log(foo(1,2,3))   //[1,2,3]

 

區別bind()、call()、apply()

  • 都能指定函數中的this
  • call()和apply是當即調用函數
  • bind()是將函數返回

  對於bind(),cal(),apply()的介紹就到這裏啦,有幫助的話就點個讚唄,歡迎評論區指正!

相關文章
相關標籤/搜索