理解建議:若是對this指向規則不瞭解的話,建議先了解this指向規則,最好還能對call和apply的使用和內部原理也有所瞭解,否則直接研究bind仍是會有些難度的。html
//html <button id="btn"></button> //js var list = { init:function(){ this.ms = "duyi"; this.dom = document.getElementById("btn"); this.bindEvent(); }, bindEvent:function(){ this.dom.onclick = this.showMessage.bind(this); }, showMessage:function(){ alert(this.ms); } } list.init();
在單對象編程中,有一種很是典型的bind()的應用,就以上面的示例來講,當出現給DOM綁定事件回調函數時,又還須要繼續保持函數的this指向原來的對象,就能夠按照示例的這種方式來實現:this.dom.onclick = this.showMessage.bind(this);編程
咱們知道call和apply能夠改變函數執行的this指向,可是call和apply都是當即執行該函數,而bind是將this指向綁定到指定的對象上,而且返回函數並維持this指向這個對象。接下來再來看看bind的參數設置示例:app
function show(x,y,z,w){ console.log(this,x,y,z,w); } var DuyiO = { x : 20 } var newShow = show.bind(DuyiO,"1","2",3); newShow(4);//Object {x: 20} "1" "2" 3 4
bind的參數和call很是相似,惟一的區別就在於除了調用bind時傳入參數外,還能夠在正式執行時傳入參數,兩次傳入參數以拼接的方式做爲函數執行的實參。可是須要注意的是,第一個參數做爲函數的this指向對象必需要在調用bind方法時傳入,若是調用bind方法不傳入任何參數,函數的this指向就會綁定到window上。好比下面這種狀況:dom
var newShow = show.bind(); newShow(DuyiO,"1","2",3,4);//Window {…} Object {x: 20} "1" "2" 3
最後還有一個基本上不會被應用到的功能,就是返回的函數被new關鍵字用來建立一個新的對象,而構造函數仍是原函數自己(第二個示例中的show)。這個功能在模仿bind源碼不能100%實現,可是也能夠間接的實現其須要的功能。函數
1.首先實現函數調用bind修改this指向即參數設置:this
1 Function.prototype.MyBind = function(target){ 2 var self = this; 3 var args = [].slice.call(arguments,1); 4 var f = function(){ 5 return self.apply( target || window,args ); 6 } 7 return f; 8 }
2.接着再來實現函數正式調用執行時傳入設置:spa
1 Function.prototype.MyBind = function(target){ 2 var self = this; 3 var args = [].slice.call(arguments,1); 4 var f = function(){ 5 var _arg = [].slice.call(arguments,0); 6 return self.apply( target || window,args.concat(_arg) ); 7 } 8 return f; 9 }
3.最後實現當返回函數被new操做符引用做爲構造函數依然指向原函數(模擬實現功能):prototype
1 Function.prototype.MyBind = function(target){ 2 var self = this; 3 var args = [].slice.call(arguments,1); 4 var temp = function(){}; 5 var f = function(){ 6 var _arg = [].slice.call(arguments,0); 7 return self.apply(this instanceof temp ? this : ( target || window ),args.concat(_arg) ); 8 } 9 temp.prototype = self.prototype; 10 f.prototype = new temp(); 11 return f; 12 }
這個模擬實現主要有兩個關鍵點須要重點理解:code
a.代碼第七行中的this instanceof temp ? this : ( target || window ):當返回函數f被new做爲構造函數引用時,這時候this指向了函數執行時內部隱式添加在變量對象上的this(這裏不清楚的話能夠參考JavaScript中的this指向規則),固然普通調用執行就是指向self。htm
b.代碼第九行和第十行爲何須要改變f的原型,這就是我前面講的模擬實現方法構造,咱們知道bind在JS內部實現的是其返回函數仍是那個原來的函數,這裏咱們多加了一層f來實現的,因此在函數被當作構造函數的時候,將f的原型指向self也能夠實現其功能,可是構造的實例對象是基於f實現的,最終構造原型鏈仍是指向self原型,該有的方法屬性依然都會有。只是在原型鏈上多了f這個包裝層。