iT邦幫忙

2021 iThome 鐵人賽

DAY 5
0
自我挑戰組

Vue.js 從零開始系列 第 5

Vue.js 從零開始:This 是什麼?

學習JavaScript也有一陣子,當有人問起This是什麼,都無法解釋的很清楚,代表理解的不夠徹底,今天來複習This的指向,是進入Vue之前,必須掌握的觀念之一。


影響 This 的是在於函式的呼叫方法,並非宣告的時機,以下的程式碼來理解這句話的意思,這邊用var來示範。

var demo = '全域變數';
function callDemo() {
  console.log(this.demo);
}
var obj = {
  demo: '物件',
  callDemo(){
    console.log(this.demo);
  }
}
callDemo();

console.log的結果是




全域變數,This的指向關鍵在於如何呼叫他,注意呼叫函式前一個的”物件“,約有九成的This是這樣指向,
接下來我們把CallDemo()前面加個物件。

var demo = '全域變數';
function callDemo() {
  console.log(this.demo);
}
var obj = {
  demo: '物件',
  callDemo(){
    console.log(this.demo);
  }
}
obj.callDemo();

console.log的結果是



物件,由這點來證明This的指向是跟呼叫方式有關係,再來幾個例子。

var demo = '全域變數';
function callDemo() {
  console.log(this.demo);
}

var warpobj = {
  demo: '外層物件',
  callDemo,
  innerObj: {
    demo: '內層物件',
    callDemo,
  }
}
warpobj.callDemo();

callDemo()前面的物件是warpobj,console.log結果當然是外層物件,再來一個陷阱題。

var demo = '全域變數';
function callDemo() {
  console.log(this.demo);
}

var warpobj = {
  demo: '外層物件',
  callDemo,
  innerObj: {
    demo: '內層物件',
    callDemo,
  }
}
warpobj.innerObj.callDemo();

console.log結果是




內層物件,注意呼叫函式前一個的”物件“不用管innerOnj前面的物件。

var demo = '全域變數';
function callDemo() {
  console.log(this.demo);
}
var obj2 = {
  demo: '物件2',
  fu() {
    callDemo();
  }
}
obj2.fu();

console.log結果是全域,原因是callDemo()前面並沒有物件,所以This指向變成全域。

最後一個範例:

var demo = '全域變數';
function callDemo() {
  var demo = "測試"
  console.log(this.demo);
}
var obj4 = {
  demo: '物件2',
  fu() {
    setTimeout(function() {
      console.log(this.demo);
    },100)
  }
}
obj4.fu();

結果是全域,Callback function大部分的This都是指向全域,只有少部分會重新定義,要避免指向跑向全域有兩種解法。

  1. vm
  2. array function

第一種解法:

var demo = '全域變數';
function callDemo() {
  var demo = "測試"
  console.log(this.demo);
}
var obj4 = {
  demo: '物件2',
  fu() {
    const vm = this
    setTimeout(function() {
      console.log(vm.demo);
    },100)
  }
}
obj4.fu();

將This指向變數vm,讓他指向固定住。

第二種解法:

var demo = '全域變數';
function callDemo() {
  var demo = "測試"
  console.log(this.demo);
}
var obj4 = {
  demo: '物件2',
  fu() {
    const vm = this
    setTimeout(() => {
      console.log(vm.demo);
    },100)
  }
}
obj4.fu();

把setTimeout改成箭頭函式,因為箭頭函式沒有自己的This,所以This會外層的函式找就是fu(),結果跟第一個解法ㄧ樣都會是'物件2'。


補充說明

Execution Context(Global)
https://ithelp.ithome.com.tw/upload/images/20210920/20118347GeMne8eQYT.png
不論何時執行JavaScript程式,都會是在執行環境內執行,我們常用的瀏覽器Browser,執行環境(Execution Context)就是你的全域執行環境(Global),Global創造了兩件事,創造了全域物件(Global Object)和特殊變數This,你還沒寫程式的時候,就已經有這兩個東西的存在,當你在開發者工具的console輸入windowc或This,會跳出長長一串的內容:
https://ithelp.ithome.com.tw/upload/images/20210920/20118347E3iIEkvCiy.png
之後再補上這段JavaScript:

var a = 'hello world!!';
function b(){

};

開發者工具就會出現我們輸入的JavaScript:
https://ithelp.ithome.com.tw/upload/images/20210920/20118347o7sWqDkrYP.png
或是直接輸入this.a或是windows.a都會有'hello world!!'的結果,代表Global Object也是一個window物件,全域情況下window也等於this,this參照window物件,但前提是執行環境要在瀏覽器Browser執行,如果是Node那情況就會不同。

參考資料


卡斯柏
重新認識 JavaScript
克服JS的奇怪部分 2-10


上一篇
Vue.js 從零開始:SPA怎麼改善SEO呢? MVC與關注點分離又是什麼?
下一篇
Vue.js 從零開始:箭頭函式
系列文
Vue.js 從零開始30

尚未有邦友留言

立即登入留言