一直以來,大家都對函式的呼叫有很多的疑惑,特別是this指標的指向。 其實理解了核心的原理之後,就很容易理解,甚至就是套用數學公式一樣!
核心原理
讓我們看看原始的函式呼叫語句,也就是call方法
function test(param){
console.log(this + " loves " + param);
}
複製程式碼
test.call("Warren", "you") //=> Warren loves you
可以看到,我們呼叫了test方法,並且把this指向Warren,傳入引數you。這就是javascript函式呼叫的核心概念。其他函式都可以參考這個概念。
簡單的函式呼叫
若果每次呼叫函式都用call,會變得很麻煩。Javascript允許我們直接呼叫test("you"),其實就相當於
function test(param) {
console.log("loves " + thing);
}
// this:
test("you")
// 相當於:
test.call(window, "you");
複製程式碼
但是這個在ECMAScript的strict模式會變成:
// this:
test("you")
// 相當於:
test.call(undefined, "you");
複製程式碼
概括就是兩條公式:
fn(...args) 就相當於 fn.call(window [ES5-strict: undefined], ...args).
(function() {})() 就相當於 (function() {}).call(window [ES5-strict: undefined).
成員函式
另一種常見的函式呼叫方法就是obj.test()
.
var obj = {
name: "Warren",
test: function(params) {
console.log(this + " loves " + params);
}
}
// this:
obj.test("you")
// 相當於:
obj.test.call(obj, "you");
複製程式碼
可以看到this指向了obj,我們之前是單獨宣告test,再看看如果將它我們關聯給其他物件。
test: function(params) {
console.log(this + " loves " + params);
}
var obj = {
name: "Warren",
}
obj.test = test;
obj.test("you")
// 仍然相當於 obj.test.call(test, "you")
test("you") // "[object DOMWindow]you"
複製程式碼
this指標根據呼叫者的變化而變化!
試下Function.prototype.bind
有時候需要根據呼叫者來改變this指向,這可以用簡單閉包來實現
var obj = {
name: "Warren",
test: function(params) {
console.log(this + " loves " + params);
}
}
var boundTest = function(params) { return obj.test.call(obj, params); }
boundTest("you");
複製程式碼
套用之前的公式 fn(...args) 就相當於 fn.call(window [ES5-strict: undefined], ...args).
boundTest("you"); => boundTest(window,"you"),但是我們在boundTest裡面已經將test的this指向了obj!
讓我們改造一下這個函式:
var bind = function(func, thisValue) {
return function() {
return func.apply(thisValue, arguments);
}
}
var boundTest = bind(obj.test, obj);
boundTest(you) // "Warren loves you"
複製程式碼
要理解上面的程式碼,只需要知道2點。
- apply 與 call的區別只是 apply接受的引數是陣列,call接受的引數是引數列表。
- arguments 是像類陣列的某個函式的所有引數 bind函式返回一個陣列,每次呼叫的時候繫結this並且接受新的引數。
上面只是為了更好理解,其實es5本來就有一個bind函式
var boundTest = obj.test.bind(obj);
boundTest(you) // "Warren loves you"
複製程式碼
以上大概就是JavaScript函式呼叫與this 指標的基本原理,只要記住這兩條公式,基本就不虛了。
fn(...args) 就相當於 fn.call(window [ES5-strict: undefined], ...args).
(function() {})() 就相當於 (function() {}).call(window [ES5-strict: undefined).