一、function.prototype.call()javascript
call 方法能夠指定this 的指向(即函數執行時所在的的做用域),而後再指定的做用域中,執行函數html
call 方法的參數,應該是對象obj,若是參數爲空或null,undefind,則默認傳參全局對象 java
var obj = {}; var f = function(){ return this; }; console.log(f() === window); // this 指向window console.log(f.call(obj) === obj) //改變this 指向 obj
若是call 傳參不是以上類型,則轉化成對應的包裝對象,而後傳入方法。例如,5 轉成number 實例,綁定f 內部 this數組
var f = function () { return this; }; f.call(5) // Number {[[PrimitiveValue]]: 5}
call 能夠接受多個參數,第一個參數是this 指向的對象,以後的是函數回調所需的入參app
function add(a, b) { return a + b; } add.call(this, 1, 2) // 3
call
方法的一個應用是調用對象的原生方法。函數
var obj = {};
obj.hasOwnProperty('toString') // false
// 覆蓋掉繼承的 hasOwnProperty 方法
obj.hasOwnProperty = function () {
return true;
};
obj.hasOwnProperty('toString') // true
Object.prototype.hasOwnProperty.call(obj, 'toString') // false
上面代碼中hasOwnProperty 是 obj 繼承來的方法,用來判斷對象是否包含自身特色(非繼承)屬性,可是hasOwnProperty 並非保留字,若是被對象覆蓋,會形成結果錯誤。oop
call
方法能夠解決這個問題,它將hasOwnProperty
方法的原始定義放到obj
對象上執行,這樣不管obj
上有沒有同名方法,都不會影響結果。this
hasOwnProperty 相關應用:https://www.cnblogs.com/weiqinl/p/8683207.htmlspa
二、Function.prototype.apply()prototype
apply 和call 做用相似,也是改變this 指向,而後調用該函數,惟一區別是apply 接收數組做爲函數執行時的參數
func.apply(thisValue, [arg1, arg2, ...])
apply
方法的第一個參數也是this
所要指向的那個對象,若是設爲null
或undefined
,則等同於指定全局對象。
第二個參數則是一個數組,該數組的全部成員依次做爲參數,傳入原函數。
原函數的參數,在call
方法中必須一個個添加,可是在apply
方法中,必須以數組形式添加。
function f(x, y){ console.log(x + y); } f.call(null, 1, 1) // 2 f.apply(null, [1, 1]) // 2
利用這一特性,能夠實現不少小功能
好比,輸出數組的最大值
var a = [24,30,2,33,1] Math.max.apply(null,a) //33
將數組中的空值,轉化成undefined,主要應用在數組遍歷中,由於數組foreach 遍歷會跳過空值,而不會跳過undefined
var a = ['a',,'b']; Array.apply(null,a) //['a',undefind,'b']
將相似於數組的對象轉化成數組
另外,利用數組對象的slice
方法,能夠將一個相似數組的對象(好比arguments
對象)轉爲真正的數組。
Array.prototype.slice.apply({0: 1, length: 1}) // [1]
Array.prototype.slice.apply({0: 1}) // []
Array.prototype.slice.apply({0: 1, length: 2}) // [1, undefined]
Array.prototype.slice.apply({length: 1}) // [undefined]
上面代碼的apply
方法的參數都是對象,可是返回結果都是數組,這就起到了將對象轉成數組的目的。
從上面代碼能夠看到,這個方法起做用的前提是,被處理的對象必須有length
屬性,以及相對應的數字鍵。
3.Function.prototype.bind()
bind 用於將函數體內的this綁定到某個對象,而後返回一個新函數
var d = new Date(); d.getTime() // 1481869925657 var print = d.getTime; print() // Uncaught TypeError: this is not a Date object.
報錯是由於,d.getTime 賦值給 print 後,getTime 內部的this 指向方式變化,已經再也不指向date 對象實例了
解決方法
var print = d.getTime.bind(d); print() // 1481869925657
bind 接收的參數就是所要綁定的對象
ar counter = { count: 0, inc: function () { this.count++; } }; var func = counter.inc.bind(counter); func(); counter.count // 1
綁定到其餘對象
var counter = { count: 0, inc: function () { this.count++; } }; var obj = { count: 100 }; var func = counter.inc.bind(obj); func(); obj.count // 101
bind 還能夠接收更多的參數,將這些參數綁定到原函數的參數
var add = function (x, y) { return x * this.m + y * this.n; } var obj = { m: 2, n: 2 }; var newAdd = add.bind(obj, 5); newAdd(5) // 20
上面代碼中,bind
方法除了綁定this
對象,還將add
函數的第一個參數x
綁定成5
,而後返回一個新函數newAdd
,這個函數只要再接受一個參數y
就能運行了。
總結:
1. call 、 apply 、bind 均能改變this 指向
2. apply 每次執行產生一個新函數,call、apply 不會
3. call ,bind 接收多個參數綁定到函數,參數單一傳入,apply 接收方式爲數組
更多詳細資料:
http://javascript.ruanyifeng.com/oop/this.html#toc7