目錄
1. call 的模擬實現
2. apply 的模擬實現
3. bind 的模擬實現
4. 三者異同
學習並參考於:
(一)call的模擬實現
call 用法 : MDN Function.prototype.call()
call()
方法使用一個指定的 this
值和可選的參數列表來調用一個函數。
call()
提供新的 this 值給當前調用的函數/方法。
1. call 實現主要思路:
-
將函數設爲對象的屬性
-
執行該函數
-
刪除該函數
另外還有考慮:
- call 函數還能給定參數執行函數
- this 參數不傳,或者傳null,undefined, this指向window對象
- 函數是可以有返回值的
2. 實現:
Function.prototype.myCall = function () {
if (typeof this !== 'function') {
throw new TypeError('error!')
}
let context = arguments[0] || window //this 參數可以傳 null,當爲 null 的時候,視爲指向 window
context.fn = this // 首先要獲取調用call的函數,用this可以獲取
let args = [...arguments].slice(1) //從 Arguments 對象中取值,取出第二個到最後一個參數
let result = context.fn(...args) //函數是可以有返回值的
delete context.fn
return result
}
3. 測試:
// 測試一下上面實現的myCall
var value = 2;
var obj = {
value: 1
}
function bar(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
}
bar.call(null); // 2
console.log(bar.myCall(obj, 'kevin', 18));
// 1
// Object {
// value: 1,
// name: 'kevin',
// age: 18
// }
(二)apply 的模擬實現
apply 用法:MDN Function.prototype.apply()
apply()
方法使用一個指定的 this
值和可選的參數數組 來調用一個函數。
apply 的實現跟 call 類似。
1. 實現:
Function.prototype.myApply = function () {
if (typeof this !== 'function') {
throw new TypeError('error!')
}
let context = arguments[0] || window
context.fn = this
let result = arguments[1] ? context.fn(...arguments[1]) : context.fn()
delete context.fn
return result
}
2. 測試:
var foo = {
value: 1
}
function bar(name, age) {
console.log(name)
console.log(age)
console.log(this.value);
}
bar.myApply(foo, ['black', '18']) // black 18 1
(三)bind 的模擬實現
bind 用法:MDN Function.prototype.bind()
bind()
方法會創建一個新函數,稱爲綁定函數。當這個新函數被調用時,bind()
的第一個參數將作爲它運行時的 this,之後的一序列參數將會在傳遞的實參前傳入作爲它的參數。
bind是ES5新增的一個方法,不會執行對應的函數,而是返回對綁定函數的引用。
1. 實現:
Function.prototype.customBind = function () {
if (typeof this !== 'function') {
throw new TypeError('error!')
}
const that = this // 首先要獲取調用bind的函數,用this獲取並存放在that中
let context = arguments[0] || window
const args = [...arguments].slice(1)
return function() {
return that.apply(context, args.concat([...arguments]))
}
}
(四)三者異同
1. 相同:
- 改變函數體內 this 的指向
2. 不同:
- call、apply的區別:call方法接受的是參數列表,而apply方法接受的是一個參數數組。
- bind不立即執行。而call或apply會自動執行對應的函數。