範圍鏈 (Scope Chain),Javascript 在決定外部參考環境的時候是以「詞彙環境 (Lexical Environment)」為準則的。
let me = 'global'
a()
function a(){
let me = 'inside'
function b(){
console.log(me)
}
b()
}
// inside
b是在a的scope所以會印出chloe2。但換個情況:
var me = 'global'
a()
function a(){
let me = 'inside'
b()
}
function b(){
console.log(me)
}
// global
這會印出global,因為對b來說他沒有me,就會往外部找,他的外部就是全域中的me:global。
那麼This又是怎麼指向的?
我們知道傳統函式的this會指向呼叫的是誰。所以下面這個例子,無意外的this都會指向window。
a()
function a(){
console.log('a',this)
function b(){
console.log('b',this)
}
b()
}
//a window
//b window
如果使用內部函數的方式:
var name = 'global'
var obj = {
name: 'obj name',
f1: function(){
console.log('f1: ', this.name);
var f2 = function(){ console.log('f2: ', this.name); }
f2();
}
};
obj.f1();
結果會是:
f1: obj name
f2: global
我們順一下思路,obj呼叫了f1,所以obj的this會指向obj,f1會印出obj name。
那麼在obj.f1()中執行的f2呢?f2沒有指定呼叫者,視為簡單呼叫,因此this會指向全域,會往外找到全域變數name: 'global'。順便提一下,如果把var name = 'global'
改成let name = 'global'
,f2()會印出undefined,因為用let的全域變數,沒有儲存在window object上面過。
試試看加上arrow function:
arrow function 的this會指向語彙位子。我們試著將f2改成arrow function
var name = 'global'
var obj = {
name: 'obj name',
f1: function(){
console.log('f1: ', this.name);
var f2 = ()=>{ console.log('f2: ', this.name); }
f2();
}
};
obj.f1();
會得到:
f1: obj name
f2: obj name
為什麼呢?
f1會得到obj name是因為是obj呼叫f1,所以this會指向obj。
f2使用arrow function,this會指向語彙位子的上一層也就是obj。
再來試著將f1改成arrow function,f2維持傳統函式。
var name = 'global'
var obj = {
name: 'obj name',
f1: ()=> {
console.log('f1: ', this.name);
var f2 = function(){ console.log('f2: ', this.name); }
f2();
}
};
obj.f1();
試著想一下會得到什麼?
f1: global
f2: global
你答對了嗎?
f1:雖然是obj呼叫f1,但f1是arrow funciton,他的this會指向語彙位子的上層,也就是window,因此會印出'global'
f2:沒有呼叫者,算簡單呼叫,因此會指向window,也會印出'global'
最後我們再來試試看,兩者都是arrow function的話會是什麼情況呢?
var name = 'global'
var obj = {
name: 'obj name',
f1: ()=> {
console.log('f1: ', this.name);
var f2 = ()=>{ console.log('f2: ', this.name); }
f2();
}
};
obj.f1();
f1: global
f2: global
f1:雖然是obj呼叫f1,但f1是arrow funciton,他的this會指向語彙位子的上層,也就是window,因此會印出'global'
f2:是arrow funciton,他的this會指向語彙位子的上層,他的語彙位子上層obj.f1的this指向window,因此f2的this指向window,所以也會印出'global'。
雖然和上一種寫法得到的結果一樣,但過程是不一樣的喔!