物件導向的運用
有了物件導向的先備知識,在物件導向的程式結構中,透過 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()