this的動態切換雖然爲js創造了巨大的靈活性,也使編程變得困難和模糊
。利用call、apply、bind這三個方法,能夠改變this的指向,使它指向咱們指望的對象。編程
var f = function() {}; f.call(o);
在全局環境運行函數時,this指向全局環境,利用call方法,將this指向了對象o,在o的做用域中運行函數f。數組
var n = 123; var o ={n: 234}; function a() {console.log(this.n)}; a.call() //123 a.call(null) //123 a.call(undefined) //123 a.call(window) //123 a.call(o) //234
能夠看到,若是call方法沒有參數,或者參數爲null或undefined,則等同於指向全局對象app
call方法的完整使用格式:函數
func.call(thisValue, arg1, arg2, ...)
第一個參數是this要指向的那個對象,後面的參數是調用時所須要的參數this
function add(a,b) { return a+b; } add.call(this, 1, 2) //3
call方法的一個應用是調用對象的原生方法prototype
var obj = {}; obj.hasOwnProperty('toString') //false obj.hasOwnProperty = function() {return true;} obj.hasOwnProperty('toString') //true Object.prototype.hasOwnProperty.call(obj, 'toString')
上述代碼中,hasOwnProperty是obj對象繼承的方法,一旦被覆蓋從新定義,就得不到正確結果,利用call方法,將hasOwnProperty方法的原始定義放到obj對象上執行,這樣不管Obj上有沒有同名方法,都不會影響結果。code
apply方法與call方法相似,使用格式以下:對象
func.apply(thisValue, [arg1, arg2, ...])
apply方法的第一個參數也是this所要指向的那個對象,若是設爲null或undefined,則等同於指定全局對象。第二個參數則是一個數組,該數組的全部成員依次做爲參數,傳入原函數。
一些有趣的應用
1)找出數組最大元素繼承
var a = [12, 2, 45, 4, 9]; Math.max.apply(null, a); //45
2)將數組的空元素變爲undefined事件
Array.apply(null, ["a",,"b"]) // ['a', undefined, 'b']
空元素和undefined的差異在於,數組的foreach方法會跳過空元素,可是不會跳過undefined,所以遍歷內部元素的時候,會獲得不一樣的結果
var a = ["a",,"b"]; function print(i) { console.log(i); } a.forEach(print) //a //b Array.apply(null, a).forEach(print) //a //undefined //b
3)轉換相似數組的對象
Array.prototype.slice.apply({0:1,length:1}) // [1] Array.prototype.slice.apply({0:1}) // [] Array.prototype.slice.apply({0:1,lengt:2}) // [1, undefined] Array.prototype.slice.apply({length:1}) // []
利用數組的slice方法,能夠將一個相似數組的對象,好比上面代碼的apply方法的參數都是對象,可是反悔結果都是數組,這就起到了將對象轉成數組的目的。
這個方法起做用的前提是,被處理的對象必須有length屬性,以及相對應的數字鍵
4)綁定回調函數的對象
這個採用bind方法更好
var o1 = new Object(); o1.p = 123; o1.m = function() {console.log(this.p);}; o1.m(); //123 var o2 = new Object(); o2.p = 345; o2.m = o1.m; o2.m(); //345 o2.m = o1.m.bind(o1); o2.m() //123
bind方法除了綁定this之外,還能夠綁定原函數的參數
var add = function (x,y) { return x*this.m + y*this.n; } var obj = { m: 2, n: 2 }; var newAdd = add.bind(obj, 5);//add()函數的第一次參數x綁定爲5,若是給了兩個參數,則同時給定了x、y的值 newAdd(5); //20
若是bind方法的第一個參數是null或undefined,等於將this綁定到全局
bind方法的使用注意點:
1)每一次返回一個新函數
element.addEventListener('click', o.m.bind(o));
click事件綁定到了o.m使用bind方法生成的一個匿名函數上,這樣會致使沒法取消。所以下面代碼是無效的。
element.removeEventListener('click', o.m.bind(o));
正確的寫法是下面這樣:
var listener = o.m.bind(o); element.addEventListener('click', listener); //... element.removeEventListener('click', listener);