iT邦幫忙

1

關於javascript 令人又愛又恨的 this

  • 分享至 

  • xImage
  •  

前言:最近開始在學新框架了,只是說原生的 javascript 也同時在補足觀念中,最近在複習 this 看當初的筆記,有一種 WTF ,我在寫什麼三小?只能當自己是白紙再看一遍了。 嗚嗚

輔助資源:
猜猜這個 "this" 到底是什麼?
https://youtu.be/8uqUD2F_W74

先說重點:

  • this 是 javascript 的一個關鍵字
  • this 是 function 執行時 自動生成的一個內部物件
  • 隨著function 執行場合不同,this 所指向的值,也有所不同
  • 多數情況下,this 代表呼叫 function 的物件

關鍵:this 決定在於函式如何被呼叫


console.log(this);

在全域執行環境呼叫this,此時它會指向全域物件,也就是window

image

// Outer Environment
console.log(this);

// function statement
function FunctionStatement() {
  console.log(this);
}
FunctionStatement();

// function expression
const FunctionExpression = function() {
  console.log(this);
}
FunctionExpression();

這裡的 this 都代表 不管是 function statement 去執行;或是 使用 function expression 執行 只要在全域定義、呼叫創造其執行環境,這時的this會指向全域物件。

var kara = " p助"
function a(){
	this.kara = "兔兔"
}

a();
console.log(kara)

console.log 答案是

兔兔 !

  • 我在全域宣告一個變數kara,賦值"p助"。

  • 呼叫函式a時,函式a的執行環境被創造出來,同時函式a的執行環境也創造了它自己的this。

  • 賦值兔兔"給函式a的this.kara,因為函式a自己的this指向全域,這下可好了,在全域的變數kara,其值被蓋過從"p助"變成了"兔兔"。

所以回到這一題,這裡的 this 就是 指全域


var name = '全域';
function callMethod () {
  var name = '區域'
  console.log(this.name)
}
callMethod();

所以使用this必須要小心,得清楚它指向的物件對象是誰,否則可能會產生一些開發上的bug。

this 代表 function 執行時所屬物件,而不是function 本身。

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

var fpp = function (){
   let a =123;
   this Qoo();

}

fpp();

答案是 undefined

因為fpp() 透過 this Qoo 取得 Qoo() 這裡的this Qoo指得是 指向 window.Qoo 。 而Qoo()的 this.a 並非fpp()中的123,而是指向 window.a 所以得到undefined 結果。

請看以下問題:

var name = '全域';
function callMethod() {
  var name = '區域'
  console.log(this.name)
  return function () {       // << 閉包
    var name = '區域的內層變數';
    console.log(this.name)
  }
}
callMethod()();

1.這裡的callMethod()() 執行的 第五行 function

那如果執行出來的結果會是什麼?

答案是: console.log 出現兩個全域

崩潰了嗎?還沒結束喔? 冷靜三秒,數一下 質數

當沒有特別指名this 的情況下, 預設的this 就是全域物件

物件下的不同函式呼叫方式,分別有三種呼叫方式

1.一般 function

var name = '全域';
var object = {
  name: 'Object 區域',
  callMethod: function () {
    var name = '區域';
    console.log(this.name);
  },

}
object.callMethod();

其中 callMethod 是一個 匿名函式(anonymous function),程式內容很簡單,就是呼叫出 this 而已。最後則是使用 object.callMethod() 的方式來執行該方法。

Ans "Object 區域"

當某個函式是放在某一個物件裡面時,那麼該函式裡面的 this 指稱的就是該物件本身。

2.函式物件縮寫 function

這是ES6的東西 可以補充

function 這個詞彙如果使用在物件內,也可以省略 :function,省略後的語意是沒有變化的,並沒有轉而使用箭頭函式。

const newTeam = {
  // ...
  showPosture: function () {
    console.log('我們是 紅黃綠')
  }
}

const newTeam = {
  // ...
  showPosture () {
    console.log('我們是 紅黃綠')
  }
}

兩個代表一樣意思。

var name = '全域';
var object = {
  name: 'Object 區域1',
  callMethod: function () {
    var name = '區域';
    console.log(this.name);
  },
  
abbCallMethod () {
    var name = '縮寫函式區域';
    console.log(this.name);
  }

}
object.callMethod();   // 
object.abbCallMethod();

第二個 abbCallMethod 就是物件函式縮寫,
所以跟第一個答案 callMethod() 所得到的答案是一樣的。

3.箭頭函式

var name = '全域';
var object = {
  name: 'Object 區域',
 
  arrowCallMethod: () => {
    var name = '箭頭函式區域';
    console.log(this.name);
  }
 
}

object.arrowCallMethod();

這裡要特別注意,箭頭函式 答案是 全域

因為 箭頭函式 特性有強制綁定 this,所以當我們在寫函式時要注意 。

DOM 物件調用

var elements = document.getElementsByTagName('div');
function style () {
  console.log(this);
  this.style.border = '1px solid red';
}
for (var i = 0; i < elements.length; i++) {
  elements[i].addEventListener('click', style, false);
}

這裡 的this 就是我們所執行的 dom 事件 的地方,點擊到的地方

函式建構式 this

var name = '全域';
var callMethod = function (newName) {
  this.name = '權權權';
  console.log(this.name);
}
var myName = new callMethod();
console.log(myName.name);

console.log 出來的答案是 權權權

因為 myName 繼承了 callMethod 方法 ,所以 myName.name
答案是 權權權

var name = '全域';
var callMethod = function (newName) {
  this.name = newName || '區域';
}
var myName = new callMethod('權權權');
console.log(this.name);
console.log(myName.name);

這裡的 this name  還是指向 全域。
myName.name 就是函式建構式 指的是 權權權。

接下來看陷阱題

 
var name = '全域';
var callMethod = (newName) => {
  this.name = newName || '區域';
}
var myName = new callMethod('卡斯伯');
console.log(this.name);
console.log(myName.name);

這裡不管是哪一個 console.log 都無法執行,因為箭頭函式不能當建構式。

bind, apply, call

基本上只要看到 bind, apply, call 裡面的this  就是代表綁定的物件

call、apply、bind 三者都是 JavaScript Function 的內建函式,他們與 this 的關係重大,除此之外,call & apply 可以作為呼叫 Function 的另一個手段,而 bind 則會回傳一個經過包裹後的 Function 回來。


function callMethod () {
  var name = '區域'
  console.log(this.name)
}
callMethod.call({name: '魯魯米'});

這裡的 callMethod 所指就是 魯魯米

bind, call, apply 的差異

可以看這篇文章:
讓你弄懂call、apply、bind的應用和區別
https://juejin.im/post/5a9640335188257a7924d5ef

影響 this 的幾種情境

  • 純粹的調用
    • window
  • 物件的方法調用
    • Object
  • DOM 物件調用
    • Object
  • 建構式的調用
    • Object > 屬於 new 它的物件
  • bind, apply, call
    • 傳入的物件
  • 箭頭函示 >箭頭函數會自動將 this 變數綁定到其定義時所在的物件
    • window 或 定義的環境

注意事項

先說結論:setTimeout中所執行函數中的this,永遠指向window!!注意是要延遲執行的函數中的this哦!


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言