[進階 js 11] this


Posted by tzutzu858 on 2021-03-30

在沒有意義的地方呼叫 this,預設值會是什麼?

this 的值取決於在什麼環境,依據環境不同,this 值也會不同
在 node.js 的 this 預設值會是 global
在瀏覽器上跑的話,this 會是 Window
但在嚴格模式,也就是設定 use strictthis 的預設值會是 undefined

'use strict'; // 開啟嚴格模式

function test() {
  console.log(this); // undefined
}
test();

DOM 元素中的 this

這邊的 this 就會是你實際做操作的東西,比如說用 click ,那 this 就是你點到哪個按鈕就是哪個按鈕

document.querySelector('.btn').addEventListener('click', function() {
  console.log(this)   
})

另外兩種呼叫 function 的方法:call 與 apply

前一篇文章有提到在模擬 new 背後在做的事情,有用到 call 這個 function
第一個參數傳的是什麼,this 就是什麼

'use strict';
function test() {
  console.log(this);
}
test.call(123);     // 123
test.call({});      // {}
test.call([1]);     // [ 1 ]

除了 .call() 還有 .apply()
.call() 一樣第一個參數就是 this 的值

那和 .call() 差異在哪 ?

差異在於 .apply() 第二個參數會是 array

function test(a, b, c) {
  console.log(this)
  console.log(a, b, c)
}

test.call(123, 1, 2, 3)
test.apply(123, [1, 2, 3])


  • this 只有在跟物件導向扯上關係的時候,this 才有意義,在這關係以外基本上沒什麼意義
  • this 在程式碼的哪邊無關,跟怎麼被呼叫有關
const obj = {
  a: 123,
  test: function(){
    console.log(this)
  }
}

obj.test()

上面程式碼的 this 是 obj 本身

const obj = {
  a: 123,
  test: function(){
    console.log(this)
  }
}

var func = obj.test
func()  // obj.test()

上面程式碼的 this 的值變成 undefined
不是同一個 function 嗎? 怎麼值就不一樣了
所以這就是前面提到的 this 在程式碼的哪邊無關,跟怎麼被呼叫有關


上述例子可以用不同角度來看會比較好理解
首先 obj.test() 可以看成 obj.test.call(obj)
假設裡面還有一層 inner

const obj = {
  a: 123,
  inner: {
      test: function(){
          console.log(this)
      }
  }
}

obj.inner.test() // 可以看成 obj.inner.test.call(obj.inner)
// 上面這樣執行, this 都是 inner 這個物件

const func = obj.inner.test
func() 
// 上面這樣執行, this 就會是 undefined
// 所以 func() 可以看成 func.call(undefined)

因為 func() 前面沒有其他東西,在 .call 可以看成傳 undefined 進去
而前面 obj.inner.test() ,test 前面還有 obj.inner. 所以在 .call 就是傳前面東西進去 obj.inner.test.call(obj.inner)


做個小測驗來了解對 this 熟不熟

'use strict';

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

var a = { a: 1, log: log };
var b = { a: 2, log: log };

log();
a.log();

b.log.apply(a)

答案

'use strict';

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

var a = { a: 1, log: log };
var b = { a: 2, log: log };

log(); // undefined
a.log(); // {a: 1, log: [Function: log] }

b.log.apply(a) // {a: 1, log: [Function: log] }

綁定 this 的值,用 .bind()

.bind() 會直接回傳一個 function
.call().apply() 會直接呼叫 function
.bind() 後即便再加 .call().apply() 都無法去改變 this 的值

const obj = {
  a: 1,
  test: function() {
     console.log(this)
  }
}

const bindTest = obj.test.bind('abc')
bindTest() // this 值是 abc
bindTest.call(123) // this 值還是 abc

arrow function 的 this

class Test{
  run() {
    console.log('run this:', this) // run this: Test {}
    setTimeout(function() {
      console.log(this) // 瀏覽器是 Window,嚴格模式下是 undefined
    }, 100)
  }
}

const t = new Test()
t.run()

但對於箭頭函式事情就變得不一樣

class Test{
  run() {
    console.log('run this:', this) // run this: Test {}
    setTimeout(() => {
      console.log(this) // Test {}
    }, 100)
  }
}

const t = new Test()
t.run()

箭頭函式裡面的 this 跟怎麼呼叫沒有關係,跟定義在程式碼哪裡比較有關係,這點比較像 Scope(作用域)的機制


參考文章
淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂
關於this綁定的四種方式










Related Posts

箭頭函式(arrow function)

箭頭函式(arrow function)

W18_後端框架 Express + Sequelize

W18_後端框架 Express + Sequelize

[C#] Asp.net Webform 使用Callback

[C#] Asp.net Webform 使用Callback


Comments