javascript Function.prototype.bind()的模擬實現
阿新 • • 發佈:2018-11-25
前言
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();