Function.prototype.call(this,arg1,arg2) Function.prototype.apply(this,[arg1,arg2]) Function.prototype.bind(this,arg1,arg2)
至於爲何,看完這篇文章你就懂了:)javascript
若是你不懂什麼是實例的話,請移步 深刻淺出面向對象和原型【概念篇1】、 深刻淺出面向對象和原型【概念篇2】
做用
返回值
返回值是你調用的方法的返回值,若該方法沒有返回值,則返回undefined。
window.a = 1 function print(b, c) { console.log(this.a, b, c) } print(2, 3) // 1 2 3 print.call({a: -1}, -2, -3) // -1 -2 -3 print.apply({a: 0}, [-2, -3]) // 0 -2 -3
call()方法的做用和 apply() 方法是同樣的,只有一個區別
call()方法接受的是若干個參數
apply()方法接受的是一個包含若干個參數的數組java
// 例子一 // Math.max()不接收數組的傳遞,咱們可使用apply方法 let answer = Math.max.apply(null, [2, 4, 3]) console.log(answer) // 4 // 注意下面三個等價 Math.max.apply(null, [2, 4, 3]) Math.max.call(null, 2, 4, 3) Math.max(2, 4, 3)
// 例子二 // 合併兩個數組 let arr1 = ['parsnip', 'potato'] let arr2 = ['celery', 'beetroot'] // 將第二個數組融合進第一個數組 // 至關於 arr1.push('celery', 'beetroot'); Array.prototype.push.apply(arr1, arr2) // 注意!!!this的意思是誰調用了push這個方法 // 因此當 this = arr1 後 // 就成了 arr1 調用了 push方法 // 因此上述表達式等價於 arr1.push('celery', 'beetroot') console.log(arr1) // ['parsnip', 'potato', 'celery', 'beetroot']
例子二
中很是值得注意的就是arr2數組被拆開了,成了一個一個的參數segmentfault
因此,apply常常性的做用之一就是
將數組元素迭代爲函數參數
// 例子三 Math.max.apply(null, [2, 4, 3]) // 完美運行 arr1.push.apply(null, arr2) // 報錯 Uncaught TypeError: Array.prototype.push called on null or undefined // 說明 Math = { max: function (values) { // 沒用到this值 } } Array.prototype.push = function (items) { // this -> 調用push方法的數組自己 // this爲null的話,就是向null裏push // Array.prototype.push called on null or undefined } // 下面三個值是徹底等價的,由於this值已是arr1 Array.prototype.push.apply(arr1, arr2) arr1.push.apply(arr1, arr2) arr2.push.apply(arr1, arr2)
function xx() { console.log(this) } xx.call('1') // ?? xx() // ??
若是答案和你想的不同,請移步 this總結【1】—— this概覽
fun.bind(thisArg[, arg1[, arg2[, ...]]])
實例使用bind()方法後會返回一個新的函數【綁定函數】
而原函數爲【目標函數】數組
我我的更喜歡用 新函數和 原函數來區分,由於新名詞越多,理解上的困難越大
那麼新函數被調用時會發生什麼呢?
下面一句話務必記住
其實就是把原函數call/apply一下,並指定你傳遞的thisapp
function xx() { console.log(this) } let foo = xx.bind({'name':'jason'}) // foo —— 新函數【綁定函數】 // xx —— 原函數【目標函數】 foo() // 新函數調用時對原函數的操做 // 下面是僞代碼 // function foo(){ // xx.call({'name':'jason'}) // } // 1.給xx(原函數)指定this 2.調用xx(原函數) // 必定要注意這兩步是在新函數被調用時才發生,不調用不發生 // 你也能夠總結爲一句話,給原函數 call/apply 了一下
function list() { // 原函數【目標函數】 return Array.prototype.slice.call(arguments); } let listTest = list(1, 2, 3); // [1, 2, 3] // 新函數【綁定函數】 let leadingThirtysevenList = list.bind(undefined, 37); let list1 = leadingThirtysevenList(); // [37] let list2 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
思考過程
// 實現bind其實就是實現bind的特色 // 1.bind的第一個參數是this // 2.bind能夠return一個新函數,這個新函數能夠調用原函數而且能夠指定其this,還能夠接受參數 // 3.bind返回的新函數傳遞的參數要在bind傳遞的參數的後面
代碼
Function.prototype._bind = function () { // 聲明bind接受的參數【除去this】爲bindArgs // 由於第一個參數是this,須要去掉 let bindArgs = Array.prototype.slice.call(arguments, 1) let bindThis = arguments[1] // 聲明原函數【目標函數】爲targetObj let targetObj = this return function () { // return出來的的函數接受的參數爲newArgs // 要在return出來的新函數裏把bindArgs和newArgs合併,使用數組的concat方法 let newArgs = Array.prototype.slice.call(arguments) return targetObj.apply(bindThis, bindArgs.concat(newArgs)) } }
你在控制檯輸入console.log(1)爲何一個是1,一個是undefined?
1是執行console.log()方法的輸出值,undefined是這個方法的返回值 因此,你要知道全部的函數都有返回值,必定要去關注一下函數的返回值
xxx.call()/xxx.apply() 的返回值是由xxx自己的返回值決定的 xxx.bind() 的返回值是一個函數