iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 16
0
Modern Web

教練我想學 JavaScript 系列 第 16

Day 16 物件、函數與「this」

  • 分享至 

  • xImage
  •  

Day 16 物件、函數與「this」

當函數被呼叫時執行環境會被創造,也會替我們創造變數環境

圖片來源:JavaScript 全攻略:克服 JS 的奇怪部分課程第 4 節講座 37 影片截圖

執行環境也會替我們創造外部參考環境(外部詞彙環境),
方便在我們找尋一個在函數中不存在的變數或函數時,
會往範圍鏈裡面去找,直到全域執行環境為止,

圖片來源:JavaScript 全攻略:克服 JS 的奇怪部分課程第 4 節講座 37 影片截圖

除此之外執行環境創造時還會幫我們創造特殊變數 this ,
this 會指向不同物件
this 會依據我們在哪裡呼叫而有所不同,

圖片來源:JavaScript 全攻略:克服 JS 的奇怪部分課程第 4 節講座 37 影片截圖

我們來看些範例,
程式碼如下:

console.log(this);

我們都知道如果我們在全域環境呼叫 this 會指向全域物件,
我們到 Chrome 的 Console 來看:

這在我們的預料之內,但我們接下來看看其他範例,

接著我們看函數,
先使用函數陳述句來新增函數,
程式碼如下:

function a() {
  console.log(this);
}

a();

我們呼叫函數 a 時,函數 a 的執行環境背創造同時也創造特殊變數 this ,
接著執行程式屬性(函數中的所有程式碼),
來看 Console 中的結果:


可以看到在全域環境創造的函數的 this 會指向全域物件 Window,

如果換成函數表達式呢?
我們一樣在全域環境下新增一個函數
程式碼如下:

var b = function() {
  console.log(this);
}

b();

函數現在被儲存到變數 b 的記憶體位址裡,
那我們呼叫它來看 this 的結果:

可以看到我們在全域環境下不管用函數陳述句或函數表達式,
當函數被呼叫時,this 都是指向到全域物件(瀏覽器的全域物件是 Window),
在全域環境創建的函數的 this 沒有指向函數本身,

我在函數中透過 this 與點(成員取用)運算子來新增屬性到全域物件 Window ,
程式碼如下:

function a() {
  console.log(this);
  this.newvariable = 'Hi';
}

a();

console.log(newvariable);

我們到 Console 中看結果:

我們不用透過 this 與點(成員取用)運算子就能直接取用到全域物件底下的 newvariable 屬性,

在物件中的函數我們稱為方法,
現在來看看這個例子,
程式碼如下:

var c = {
  name: 'The c object ',
  log: function() {
    console.log(this);
  }
}

c.log();

我們到 Console 中看結果:

現在物件中的方法(函數),被呼叫時執行環境被創造,同時創造特殊變數 this ,
在這個物件的方法裡的 this 指向物件(變數 c)本身,

在物件中可以透過 this 修改屬性或方法,
我們修改一下剛才的程式碼,
程式碼如下:

var c = {
  name: 'The c object ',
  log: function() {
    this.name = "Updated c object",
    console.log(this);
  }
}

c.log();

這時屬性 name 會被修改成新的內容,
Console 中的結果:

在物件的方法中可以透過 this 來取用物件的屬性與方法,

如果方法中又有其他函數情況會不太一樣,
程式碼如下:

var c = {
  name: 'The c object ',
  log: function() {
    this.name = "Updated c object";

    var setName = function (newName) {
      this.name = newName;
    }

    setName('Updated again c object');
    console.log(this);
  }
}

c.log();

到 Console 中來看結果:

會發現物件方法中的函數 setName 並沒有修改到物件的 name 屬性,
屬性的值還是跟剛才一樣,
這時可以從全域物件 Window 中找到,
如下圖:

我們可以在 Console 中 輸入 window 來查看,會發現 name 屬性被新增到全域物件 Window 底下

物件方法中的函數的 this 跟我們想像的不一樣,他不是指向物件本身,而是全域物件 Window,

要解決這個情況可以使用另一種方式,
程式碼如下:

var c = {
  name: 'The c object ',
  log: function() {
    var self = this;
    self.name = "Updated c object";

    var setName = function (newName) {
      self.name = newName;
    }

    setName('Updated again c object');
    console.log(this);
  }
}

c.log();

我們在物件的 log 方法第1行使用一個變數 self 來儲存 this ,
這會讓 self 與 this 指向同一個記憶體位址,我們知道物件是 by reference 的,
現在在方法裡與方法中的函數裡都改用 self 變數來取用屬性,
我們到 Console 中看是否如我們的預期 ,
Console 中的結果如下:

透過這個方式物件的 log 方法中的子函數也可以取用到物件裡的屬性了,因為變數 self 與物件的 this 現在指向同一個記憶體位置,

現在我們知道呼叫函數時也會創造特殊變數 this ,
透過 this 來修改屬性值是非常長用到的技巧,
不過要小心你的 this 是不是你要的 this。


上一篇
Day 15 By Value 與 By Reference
下一篇
Day 17 陣列
系列文
教練我想學 JavaScript 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言