天天看點

apply、call與bind函數的模拟實作

this是函數調用時産生的對象,該對象綁定函數調用時所在執行環境。

call/bind方法在使用一個指定的 this 值和若幹個指定的參數值的前提下調用某個函數或方法。
function myApply(obj = window,[...args]){//接受第二個參數為數組
	obj.fn = this
	const res = obj.fn(...args)
	delete fn			//delete可以删除對象的屬性。詳細參考對象的屬性(資料屬性和通路器屬性)
	return res
}
function myCall(obj = window, ...args){
	obj.fn = this
	const res = obj.fn(...args)
	delete fn
	return res
}
           
bind() 方法會建立一個新函數。當這個新函數被調用時,bind() 的第一個參數将作為它運作時的 this,之後的一序列參數将會在傳遞的實參前傳入作為它的參數。(來自于 MDN )
實作要點:
1、傳回值為函數
2、函數調用時this指向于傳入對象
3、函數可傳遞參數
4、該函數可作為構造函數

第一版:實作1~3
Function.prototype.myBind = function (obj = window, ...args){
	let self = this
	return function(...params){
		return self.apply(obj, args.concat(params))
	}
}

第二版:實作4
作為構造函數調用時,使用new關鍵字。該關鍵字将this指向生成執行個體,是以實際調用時this指向執行個體。
Function.prototype.myBind = function (obj = window, ...args){
	let self = this
	function F = function (...params){
		
		return self.apply(this instanceof F ? this : obj, args.concat(params)) 
	} 
	//修改傳回函數的 prototype 為綁定函數的 prototype,那麼執行個體就可以繼承綁定函數的原型中的值
	F.prototype = self.prototype
	//F與self共用一個原型
	//如果直接修改F.prototype,則self.prototype也會變化,做一個優化
	return F
}
逐句講解:
```js
//建立函數并傳回該函數
	function F(){} 
	//...
	return F
	
// this instanceof F 若作為構造函數調用,則this指向執行個體
//不作為構造函數調用時, this指向傳入對象obj
self.apply(this instanceof F ? this : obj, args.concat(params)) 
           

第三版:優化傳回函數原型

function myBind (obj = window, ...args){
	let self = this
	function F = function (...params){
		return self.apply(this instanceof F ? this : obj, args.concat(params)) 
	} 
	function f (){}
	f.prototype = self.prototype
	F.prototype = new f()
	return F
}