JavaScript 進階 05:this


物件導向的運用

有了物件導向的先備知識,在物件導向的程式結構中,透過 this 來存取到目前對應的 instance。

function Dog(name) {
    this.name = name // this 指向 d function
}
Dog.prototype.getName = function() {
    return this.name
}
Dog.prototype.sayHello = function() {
    console.log(this.name)
}
var d =  new Dog('abc')
d.sayHello()

在非物件導向環境

依據環境的不同,印出的值也會不同,但都會是一個全域的屬性。

Node.js

function test() {
    console.log(this === global)
}
test()
// 印出 true

瀏覽器

function test() {
    console.log(this === window)
}
test()
// 印出 true

嚴格模式

瀏覽器 & Node.js 皆會印出 undefined

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

function test() {
    console.log(this)
}
test()
// 印出 undefined
'use strict' // 開啟嚴格模式

function test() {
    console.log(this)
}
test()
// 印出 undefined
  • this 放置位置無關
'use strict' // 開啟嚴格模式

function test() {
    var a = 1
    function inner() {
        console.log(this)
    }
    inner()
}
test()
// 印出 undefined
  • 但是有例外:DOM 操作環境
document.querySelector('.btn').addEventListener('click', () => {
    this //  this 即指向實際去做操作的東西; this = 'click'
})

call 和 apply

呼叫 function 的方式一:call

呼叫 test() 並將 this 換成傳入的值

'use strict'

function test() {
    console.log(this)
}
test.call(123)  // 你傳的值是什麼,this 就是什麼

呼叫 function 的方式二:apply

'use strict'

function test() {
    console.log(this)
}
test.apply(123)  // 你傳的值是什麼,this 就是什麼

兩者的差別在哪裡?

'use strict'

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]) //只會傳入兩個參數
// 印出皆為
// 123
// 1 2 3
// 最重要的一件事,都可以改變 this 的值

用另一個角度理解 this

this 跟程式碼的位置無關,跟怎麼呼叫有關

'use strict'

const obj = {
    a: 123,
    test: function() {
        console.log(this) // obj
    }
}
obj.test()
// 印出 {a: 123, test: [function: test]}, 即是 obj 本身
===
const d = new Dog()
d.test 呼叫的形式一樣
  • 舉個例子
'use strict'

const obj = {
    a: 123,
    test: function() {
        console.log(this) // obj
    }
}
var func = obj.test
func() // obj.test()
// 印出 undefined (this)
===
obj.test() => obj.test.call(obj)
'use strict'

const obj = {
    a: 123,
    inner: {
        test: function() {
            console.log(this)
        }
    }
}
obj.inner.test() 
obj.inner.test.call(obj)
// 都會印出 {test: [Function: test]}
===
const func = obj.inner.test
func() => func.call(undefined)
===
obj.inner.test => obj.inner.test.call(obj.inner)
obj.test => obj.test.call(obj)

綁定 this:bind

  • 牛刀小試
'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);
// 印出 undifined, {a:1, log: log}, {a:1, log: log}
  • 想要有個函式,怎麼呼叫 this 值不會變
'use strict'

const obj = {
    a:1,
    test: function() {
        console.log(this)
    }
}
const bindTest = obj.test.bind(11111)  
// 用 bind,把 this 綁定好之後,回傳一個 function

bindTest() 回傳 1111
bindTest.call(123) 回傳 1111

箭頭函式的 this

  • 牛刀小試 @ 瀏覽器
class test() {
    run() {
        console.log('run this:' this)
        setTimeout(function() {
            console.log(this)
        }, 1000
    }
}
const t = new Test()
t.run()
// 印出 Test()
// window ()
  • 改成箭頭函式
    箭頭函式下的 this,跟你怎麼呼叫沒有關係;反而跟 Scope 的機制比較像,跟 this 定義在哪裡比較有關係。
class test() {
    run() {
        console.log('run this:' this)
        setTimeout(() => {
            console.log(this) // 去用上一層定義的 this
        }, 1000
    }
}
const t = new Test()
t.run()
// 印出 Test()
// 印出 Test()







你可能感興趣的文章

npm 和 npx 的差別

npm 和 npx 的差別

[Oracle SQL Debug] 解決Unpivot時,Null值被剔除的問題

[Oracle SQL Debug] 解決Unpivot時,Null值被剔除的問題

學習 Git (4) - 淺談 Commit 規範

學習 Git (4) - 淺談 Commit 規範






留言討論