首先我要先搞懂這三個方法怎麼用數組
1. call( )
語法app
fun.call(thisArg, arg1, arg2, ...)
第一個參數理解爲要在哪裏執行fun(運行時指定的this值,他不必定是該函數執行時真正的this值,若是這個函數處於非嚴格模式下,則指定爲null和undefined的this值會自動指向全局對象),後面的一串參數意思是執行fun時的傳參函數
返回值是你調用的方法(fun)的返回值,若該方法沒有返回值,則返回undefinedthis
實現call開始prototype
// 首先沒有給一個傳入參數形式context Function.prototype._call(context){ // 就要判斷實際調用有沒有這個參數 let context = context ? context : window // 此時這個context就替代了上面的target context.func = this let result = context.func(args) // 拿參數這步省略了,無錯,按照我本身的寫法這樣也能夠 /* let [target, ...args] = [...arguments] 判斷了傳入的目標對象是null等狀況,再賦值window實際也能成功 if(target == null || undefined){ target = window; } */ return result // 別忘記刪除方法,這句寫在return前面 delete context.func } // 最終我本身不看答案寫出的結果以下,實測能夠 不知道有沒有潛在問題 Function.prototype._call = function(){ // let cont = context ? context : window let [target, ...args] = [...arguments] if(target == null || undefined){ target = window; } target.fn = this let result = target.fn(...args) delete target.fn return result }
2.apply( )
語法指針
fun.apply(obj,args)
第一個參數仍然理解爲要在哪裏執行fun,第二個參數是一個數組。code
兩種方法意思是同樣的,只是傳參方式不一樣。call後面能夠給不少,而apply就只能給一個數組,在實際狀況中按需使用吧。(我今天看懂繼承再看看能多說點什麼,還有試一下apply的返回是否是同樣)對象
實現apply開始繼承
Function.prototype._apply = function(){ // 一切和call都差很少 let [target, ...args] = [...arguments] // 考慮不傳參 做用域的狀況 if(target == null || undefined){ target = window } target.fn = this let result // 考慮參數存在狀況。 if(args){ // 這裏踩坑了,實際調用過程仍是會把數組轉化成非數組的 要加上... result = target.fn(...args) }else{ result = target.fn() } delete target.fn return result // 有了call作鋪墊基本還行,主要是判斷args是否存在,還有參數是 數組的問題 }
3.bind( ) ip
bind 是返回新的函數,以便稍後調用;apply 、call 則是當即調用原函數。也就是說 要定義一個新的變量 把bind返回的方法賦予給這個變量再去執行
語法
fun.bind(thisArg[, arg1[, arg2[, ...]]])
第一個參數我已經能夠理解了,這裏有一個新特性,就是若是bind返回的函數以new的形式去調用,第一個參數會被忽略,this仍然指向被調用的函數(fun)
arg1, arg2, … (可選)當綁定函數被調用時,要將這些參數(若是有的話)做爲bind()的參數寫在this後面。當綁定函數被調用時,這些參數會被插入到目標函數的參數列表的開始位置,傳遞給綁定函數的參數會跟在它們後面。
也就是說bind能夠實現預設一些函數參數的功能(有啥用)
如下有兩個例子來表達上面兩點,搜來的:
function original(x){ this.a=1; this.b =function(){return this.a + x} } var obj={ a:10 } var newObj = original.bind(obj,2) //傳入了一個實參2 var newObjChild = new newObj() console.log(newObj.a) //輸出 1, 說明返回的函數用做構造函數時obj(this的值)被忽略了 console.log(newObj.b()) //輸出3 ,說明傳入的實參2傳入了原函數original
var sum = function(x,y) { return x + y }; var succ = sum.bind(null, 1); //讓this指向null,其後的實參也會做爲實參傳入被綁定的函數sum succ(2) // => 3: 能夠看到1綁定到了sum函數中的x
另外的,bind和函數柯里化好像有點關係,一下子回家討論下
實現bind開始
bind好難我本身寫不出來,只好一遍一遍看了
Function.prototype._bind = function(context){ if(typeof this !== 'function'){ throw new TypeError('被綁定的對象須要是函數') } var self = this // 保存起原指針(做用域) var args = [].slice.call(arguments, 1) console.log(arguments) // =====> bind被調用時的傳入參數 fBound = function(){ // this instanceof fBound === true時,說明返回的fBound被當作new的構造函數調用 console.log(arguments) // =====> bind返回的函數fBound被調用時傳入的參數 return self.apply(this instanceof fBound ? this : context, args.concat([].slice.call(arguments))) /* 若是被Fbound被用做了構造函數, 構造出的實例必定是Fbound類型, 若是沒有,那麼當前的this和Fbound沒有任何關係。 參數爲bind被調用時和Fbound被調用時的參數聯合 */ } // ----------------------------------------------- var func = function(){} // 這個究竟是幹嗎的?? //維護原型關係 console.log(this.prototype) // 一個constructor指向原函數 console.log(func.prototype) // 什麼都沒有 if(this.prototype){ func.prototype = this.prototype } //使fBound.prototype是func的實例,返回的fBound若做爲new的構造函數,新對象的__proto__就是func的實例 fBound.prototype = new func() // ------------------------------框住的我先不看了 不能理解 return fBound }
留一個最新的MDN的polyfill
Function.prototype.bind = function() { var thatFunc = this, thatArg = arguments[0]; var args = slice.call(arguments, 1); if (typeof thatFunc !== 'function') { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError('Function.prototype.bind - ' + 'what is trying to be bound is not callable'); } return function(){ var funcArgs = args.concat(slice.call(arguments)) return thatFunc.apply(thatArg, funcArgs); }; };