1. 程式人生 > >javascript Function.prototype.bind()的模擬實現

javascript Function.prototype.bind()的模擬實現

前言

Javascript提供的內建函式Function.prototype.call(),Function.prototype.apply(),Function.prototype.bind()允許我們顯示的繫結函式執行時的this,其原理使用了超程式設計技術,這種技術的背後是JS引擎根據變數,函式,物件的內建屬性和元屬性來決定執行方式。而模擬實現只是近似模擬與內建函式相同的行為,但遠沒有內建函式精妙,也不可作為解釋內建函式的理論依據。能讓Javascript跑起來的是JS引擎,只有懂JS引擎的工作原理才能讓我們探視到內建函式的真面目,這也是我們深入瞭解後要檢視的領域。

我們入門時需要學習什麼?我們能夠學習到什麼?任何知識的學習像一個爬樓梯的過程,爬的越高,越心曠神怡,醍醐灌頂。我們入門時需要學會的是一種推導能力,用已學知識推導新知識;一種想象能力,想象那些可能性,然後大膽嘗試,找到答案。

1. bind()原理

一個函式執行需要具備3個已知條件:函式引用(必須),this繫結(可選),arguments(可選)。而內建函式bind恰恰使用3個屬性記錄這3個東西。baz是bind()返回的硬繫結函式,baz.name記錄了目標函式的名字,[[TargetFunction]]屬性記錄目標函式,[[BoundThis]]記錄目標函式執行時繫結的this,[[BoundArgs]]記錄目標函式執行時繫結的實參。

2. 自定義myBind模擬Bind()功能

		Function.prototype.myBind = function (oThis){
			//debugger;
			if(typeof this!=="function") {
				throw new TypeError("Function.prototype.myBind-what" + "is trying to be bound is not callable")
			};

			//區域性變數aArgs儲存myBind函式的實參
			var aArgs = Array.prototype.slice.call(arguments,1),

			fToBind = this,
			fNOP = function (){},//聖盃模式,用於建立fBound函式原型的中間函式
			fBound = function () {
				return fToBind.apply( 
					(
					//fNOP.prototype在New fBound()構造的例項的原型鏈上
					this instanceof fNOP && oThis ? this: oThis),

					//拼接myBind函式的實參和硬繫結函式fBound的實參後,傳遞給目標函式fToBind
					aArgs.concat(Array.prototype.slice.call(arguments)
					));
				 };

			//聖盃模式
			fNOP.prototype = this.prototype;
			fBound.prototype = new fNOP();
			//fBound.prototype.constructor = fBound;
			//fBound.prototype.uber = this.prototype;
			return fBound;
		};

		debugger;
		function foo(a,b) {
			this.a = a;
			this.b = b;
		}

		var obj1 = {};
		var baz = foo.myBind(obj1,2);
		baz(3);
		console.log(obj1);//{a:2,b:3}

		var obj2 = new baz(4);//fBound {a:2,b:4}
		console.log(obj2);

允許new進行覆蓋的部分是這裡:

this instanceof fNOP && oThis ? this : oThis

// .....和

fNOP.prototype = this.prototype;

fBound.prototype = new fNOP();