JavaScript(2):深入了解This的指向與應用

JavaScript this指向跟調用關係有關


Blog背景圖

一個函式中包含多少參數

1
2
3
4
5
var a = '全域'
function fn(params) {
console.log(params, this, window, arguments);
}
fn(100, 200, 300)
  • 每個Function都擁有paramsarguments
    • params(參數):參數是函式定義中所列出的變數
      • 100
    • arguments(引數):引數是當我們呼叫函式時傳遞給它的值
      • [100, 200, 300]
      • 這個是類陣列(Array-like):意思就是他不是真的陣列,有一些方法他並無法使用,雖然他可以查看長度,以及變更參數的值,但是他不是純陣列。
    • this(隱含的引數):根據調用的方式指向的位置不同(這邊是全域變數也就是window)
  • window:預設的全域變數。

  • 接著讓我們來了解不同情況的this的指向(以調用的方式為主)
  • 這邊this是callSomeone的孩子,本身自己調用函式的情況下this會指向全域(window)變數,也就是全域變數的someone。
1
2
3
4
5
var someone = '全域';
function callSomeone() {
console.log(this.someone);
}
callSomeone();

顯示如下:

1
全域

案例1.傳統函式this指向

  • 當前案例this是callSomeone的小孩。
  • 調用的方式改成透過obj去調用這個callSome,這時候this會改指向前面的這個怪叔叔,也就是obj,所以這邊的this已經不是window,已經改變成obj,自然this.someone就會變成obj裡面的someone。
1
2
3
4
5
6
7
8
var someone = '搗蛋鬼'
var obj = {
someone: '物件',
callSomeone() {
console.log(this.someone);
}
}
obj.callSomeone();

顯示如下:

1
物件

案例2.引用傳統函式this指向(小小變形一下)

  • 雖然原本定義在obj裡面的function變成引用外面的function,但調用的方式依然是obj2.callSomeone(),傳統函式的情況大多符合這種規則。
1
2
3
4
5
6
7
8
9
var someone = '全域';
function callSomeone() {
console.log(this.someone);
}
var obj2 = {
someone: '物件2',
callSomeone
}
obj2.callSomeone();

顯示如下:

1
物件2

案例3.夾帶兩層函式的this指向

  • 這邊可以看到wrapObj.callSomeone()這個是由wrapObj調用,因此this會指向wrapObj這個物件,自然就會將this.someone定義成外層物件。
  • 而wrapObj.innerObj.callSomeone()調用的人改變成innderObj,因此調用的this.someone將會定義成innerObj裡面的內層物件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

var someone = '搗蛋鬼';
function callSomeone() {
console.log(this.someone);
}
var wrapObj = {
someone: '外層物件',
callSomeone,
innerObj: {
someone: '內層物件',
callSomeone,
}
}
wrapObj.callSomeone()
wrapObj.innerObj.callSomeone();

顯示如下:

1
2
外層物件
內層物件

特殊案例1.間接使用this函式

  • 我們來看看特別一些的案例,記清楚剛剛說過this只取決於調用他的人是誰,callSomeone前面並沒有人使用它,因此他的this會指向全域(陷阱題)。
1
2
3
4
5
6
7
8
9
10
11
var someone = '搗蛋鬼';
function callSomeone() {
console.log(this.someone);
}
var obj3 = {
someone: '物件 3',
fn() {
callSomeone();
}
}
obj3.fn();

顯示如下:

1
搗蛋鬼

特殊案例2.setTimeout回調函式

  • 大部分傳統函式的情況下,遇到回調函式,this會指向全域變數,因此this.someone會變成搗蛋鬼。
1
2
3
4
5
6
7
8
9
10
var someone = '搗蛋鬼';
var obj4 = {
someone: '物件 4',
fn() {
setTimeout(function () {
console.log(this.someone);
});
}
}
obj4.fn();

顯示如下:

1
搗蛋鬼