iT邦幫忙

2022 iThome 鐵人賽

DAY 25
0
自我挑戰組

那些 Notion 中的前端筆記系列 第 25

Day25 | JS 函式 This 的運作

  • 分享至 

  • xImage
  •  

❒ 大部分 this 的運作模式

先判斷程式碼是傳統函式或箭頭函式

  • 傳統函式中的 this 只與調用方式有關,與怎麼定義 this 無關
    • 呼叫函式時,前面有任何物件 this 就會指向它,如果 this 前沒有任何物件會指向全域。( 下方會有範例 )
    • setTimeout 為 callback function 是 simple call 的一種形式,在傳統函式寫法下 this 會指向全域,為了避免 setTimeoutthis 指向全域可使用「 箭頭函式 」或是「 指向其他變數 」。( 最後範例 8 )
  • 箭頭函式沒有自己的 this,會看外層函式的 this 指向。
  • 宣告方式不同 ( varconstlet ) ,this 也會不同,要留意。

❒ #1 一個函式中包含多少參數

var a = '全域'
function fn(params) {
  console.log(params, this, window, arguments);
  debugger;
}
fn(1, 2, 3);

執行 debugger ,開發者工具會跳到 Sources 區域
// 執行 debugger ,開發者工具會跳到 Sources 區域 ▲

console.log(params, this, window, arguments); → 中為運行函數本身就可以執行的參數內容

  • params 為外部傳入的參數。
    • 下方程式碼中預設參數只接收一個所以顯示 1。
  • this 目前是指向 windows ,但實際在運作時可能會有很多種不同的指向,此指向會影響在使用框架時指到哪,如果想要指向特定的元件但卻指向錯誤,就會出錯。
  • window 瀏覽器本身就存在的全域變數。
  • arguments 傳統函式會帶入的參數,為類陣列會帶入所有傳入的參數內容。
    • 程式中 fn(1, 2, 3); 有三個參數 arguments 會列出所有參數值。

❒ #2 this 的指向為何

var obj = {
  name: '小明',
  fn: function(params) {
    console.log(params, this, window, arguments);
    // debugger;
  }
}
obj.fn(1 , 2 , 3);

fn: 的函式程式碼與 #1 範例相同,但卻只有 this 有所不同。

  • 1 為外部傳入的參數
  • {name: "小明", fn: ƒ}this
    開發者工具截圖

❒ #3 注意:this 的指向相當複雜,大部分情境只需要了解其中一種即可(95%)

傳統函式中的 this 只與調用方式有關,與怎麼定義 this 無關 。

大部分情境只須了解其中一種,請看下方 #4 this 的各種運用變化 | this 的判斷方式

//使用 const 與 let 結果會有所不同,所以變數someone 請使用 var 來設定全域變數。
var someone = '全域';
function callSomeone() {
  console.log(this.someone);
}
callSomeone();  //這種呼叫方式稱 simple call

// output 全域。
// 如下方所述呼叫函式 callSomeone(); 時前方沒有任何物件,所以指向全域。

❒ #4 this 的各種運用變化 | this 的判斷方式

this 的判斷 : ( 此判斷方式以傳統函式為主,箭頭函式的判斷法請看 #5 this 陷阱 )

  • 呼叫函式時,前面有任何物件 this 就會指向它 ( 例 : #4 );
  • 呼叫函式時,如果前方沒任何物件就會指向全域 ( 例 : #3 的 simple call )。

範例 1.

var someone = '全域';
function callSomeone() {
  console.log(this.someone);
}
var obj = {
  someone: '物件',
  callSomeone() {
    console.log(this.someone);
  }
}
obj.callSomeone();   

// output 物件。入上述判斷callSomeone()前方有物件 obj所以指向'物件'

呼叫函式時,前面有任何物件 this 就會指向它
// 呼叫函式時,前面有任何物件 this 就會指向它 ▲

範例 2.

var someone = '全域';
function callSomeone() {
  console.log(this.someone);
}

var obj2 = {
	someone : '物件2',
	callSomeone   //ES6 縮寫 ,原始為 callSomeone : callSomeone()
}
obj2.callSOmeone();   

 

//output 物件2
  • 變數 obj2 裡的 callSomeone 指向 function callSomeone()
  • 呼叫函式時,前面有任何物件 this 就會指向它,所以 this 指向變數 obj2。

範例 3.

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

  • 下方程式碼中,外層與內層的物件 callSomeone 皆使用函式 callSomeone()
  • 呼叫函式時,前面有任何物件 this 就會指向它。
    • wrapObj.callSomeone(); → 所以 this 指向 wrapObj,輸出 外層物件
    • wrapObj.innerObj.callSomeone(); → 所以 this 指向 innerObj,輸出 內層物件

範例 4.

var someone = '全域';
function callSomeone() {
  console.log(this.someone);
}
var obj3 = {
	someone: `物件 3`,
	fn() {
		callSomeone();    //通常不會這樣去取用 this
	}
}
obj3.fn();
  • this 與怎麼定義無關,只和調用方式有關,調用這個 fn() 內的 callSomeone() 函式時前方沒有看到任何物件,就屬於 simple call 會指向全域。
    • obj3.fn(); → output 全域
    • ‼️ 注意 : 通常會於物件下的方式調用 this,不會使用 simple call 方式去取得 this,結果可能會不如預期,這邊解說範例用。
      https://ithelp.ithome.com.tw/upload/images/20221009/20119743945158YBcK.png

範例 5.

var someone = '全域';
function callSomeone() {
  console.log(this.someone);
}
var obj4 = {
  someone: '物件 4',
  fn() {
    //callback  function
    setTimeout(function () {
      console.log(this.someone);
    });
  }
}
obj4.fn();
  • callback function 大部分屬於 simple call 形式,所以 this 大多會指向全域,少數會重新定義。
    所以 callback function 也盡可能不要調用 thisMDN - 回呼函式(callback function)
    • obj4.fn(); → output 全域

範例 6. 請問以下 this 的結果是甚麼 ?

var obj = {
    data: {
        myName: 'hexschool',
    },
    getName: function () {
        console.log(this.data.myName);
    }
}
obj.getName();
  • getName: function () 為傳統函式,傳統函式的 this 都會看前方呼叫它的是誰。
  • obj.getName(); 結果為 hexschool。

範例 7. 請問以下 this 的結果是甚麼 ?

var obj = {
    data: {
        myName: 'hexschool',
    },
    getName: () => {
        console.log(this.data.myName);
    }
}
obj.getName();
  • 箭頭函式沒有自己的 this。它會看外層函式作用域中的 this 指向,如果外層沒有函式則會指向全域。
    這邊全域沒東西,所以結果如下。
  • obj.getName(); 結果為 TypeError: Cannot read property 'myName' of undefined

範例 8.

var myName = '小明';
var obj = {
    myName: '小美',
    x: function () {
        var myName = '小王';
        setTimeout(function () {
            console.log(this.myName);
        }, 0);
    },
    y: '2',
}
obj.x();
  • setTimeout(function (){}) 為 callback function ( 大部分屬於 simple call 形式 ),會指向全域。
    但要注意,如果 callback function 這邊改為箭頭函式指向就會改變。
  • obj.getName(); 結果為 小明。

參考資訊

  • Vue 3 實戰影音課程 2021

上一篇
Day24 | JS 關於物件的傳參考、淺層拷貝、深層拷貝
下一篇
Day26 | JS 箭頭函式
系列文
那些 Notion 中的前端筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言