JavaScript 中有三個方法Function.prototype.call()
、Function.prototype.apply()
和Function.prototype.bind()
能夠用來指定函數 this 值。call()
和 apply()
相似,都是調用函數,並指定函數的 this 值thisArg
和參數,區別在於call()
傳入參數是經過參數列表的形式arg1, arg2, ...
,apply()
傳入參數是經過數組的形式[arg1, arg2, ...]
:數組
function.call(thisArg, arg1, arg2, ...) function.apply(thisArg, [arg1, arg2, ...])
bind()
方法與前兩個不一樣,它建立一個新的函數,在調用新函數時,會調用原函數,並指定原函數的 this 值和參數。bind()
執行的時候並無調用函數。bind()
傳入參數的方式和call()
同樣,都是用參數列表:app
fucntion.bind(thisArg, arg1, arg2, ...)
使用call()
調用父類構造函數來實現繼承,也能夠用apply()
,只不過傳參方式略有區別:函數
// 使用 call 實現繼承 var Pet = function (name, age) { this.name = name this.age = age } var Cat = function (name, age, color) { Pet.call(this, name, age) this.color = color } var cat = new Cat('Garfield', 1, 'orange') console.log(cat.name) // Garfield console.log(cat.age) // 1 console.log(cat.color) // orange // 使用 apply 實現繼承: var Dog = function (name, age, size) { Pet.apply(this, [name, age]) this.size = size }
當調用一個對象的方法時,方法中 this 指向的是對象自己,用call()
改變方法的 this 值:this
var utils = { setName: function (name) { this.name = name } } // 使用 call 指定 setName 中的 this 指向本身 var Person = function (name) { utils.setName.call(this, name) } var p = new Person('John') console.log(p.name) // 'John'
apply()
方法除了用來指定函數 this 值,還能夠用來傳遞參數。例如,Math.max()
容許傳入多個參數,求它們的最大值,能夠用apply()
方法將數組元素做爲參數傳遞給Math.max()
方法:prototype
// 使用循環求最大值 var numbers = [1, 0, 0, 8, 6], max = -Infinity for (var i = 0; i < numbers.length; i++) { max = Math.max(numbers[i], max) } // 使用 apply 求最大值,代碼更簡潔 var numbers = [1, 0, 0, 8, 6] max = Math.max.apply(null, numbers) // 使用 apply 給數組添加元素 var numbers = [1, 0, 0, 8, 6], arr = [] arr.push.apply(arr, numbers)
另外,由於 JS 引擎有參數長度的限制,若是參數數組太長,可能會形成程序異常。因此,對於超長參數數組,應切分紅更小的尺寸,分屢次調用該方法。code
在給setTimeout
和setInterval
傳入函數時,函數中 this 指向的是全局 window 對象。使用bind()
方法,從新指定 this 值:對象
var Person = function (name) { this.name = name } Person.prototype.say = function () { setTimeout(function () { console.log('My name is ' + this.name) }.bind(this)) } var p = new Person('John') p.say() // My name is John
在給 Dom 對象添加監聽函數時,監聽函數做爲 Dom 對象的一個方法,函數中 this 指向的是 Dom 對象。使用bind()
方法,從新指定 this 值,使用箭頭函數也能夠達到一樣的效果:繼承
var fakeDom = { a: 'fakeDom' } var addEvent = function () { this.a = 'addEvent' fakeDom.onClick = function () { console.log(this.a) } fakeDom.onClickBind = function () { console.log(this.a) }.bind(this) fakeDom.onClickArrow = () => { console.log(this.a) } } addEvent() fakeDom.onClick() // 'fakeDom' fakeDom.onClickBind() // 'addEvent' fakeDom.onClickArrow() // 'addEvent'
使用bind()
綁定參數後,新函數只須要傳入剩餘參數:ip
var add = function (a, b) { return a + b } var add5 = add.bind(null, 5) console.log(add5(3)) // 8