咱們都知道call,apply,bind函數都是爲了改變this的指向,那麼對於三種函數有什麼相同點有什麼不太點或者有什麼應用呢?下面咱們來進行介紹javascript
在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的特色,咱們能夠有如下應用。函數
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
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
<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
var arr1 = [1,"xixi",{age:17},34] var arr2 = [3,"haha",{age:44},21] Array.prototype.push.apply(arr1,arr2)//進行數組的鏈接 console.log(arr1)
var arr1 = [1,3,4,5,93] //實際爲向Math.max中傳入參數arr1,等同於Math.max(arr1) var max = Math.max.apply(Math.max,arr1) console.log(max)
與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綁定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()
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(),cal(),apply()的介紹就到這裏啦,有幫助的話就點個讚唄,歡迎評論區指正!