學習筆記:call、apply和bind

this的動態切換雖然爲js創造了巨大的靈活性,也使編程變得困難和模糊
。利用call、apply、bind這三個方法,能夠改變this的指向,使它指向咱們指望的對象。編程

call

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

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方法更好

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);
相關文章
相關標籤/搜索