[JavaScript] 纯文本查看 复制代码
function Human (age) {[/size][/font][/color][/p]this.age = age
}
let greg = new Human(22)
let thomas = new Human(24)
console.log(greg) // this.age = 22
console.log(thomas) // this.age = 24
向对象实例
你可以看到greg是Human对象的一个实例。现在,无论何时你引用greg,你不会意外地获取到thomas。所以,设置this为对象的一个实例是非常有意义的。
接下来看一个紧密相关的环境 – 对象方法中的this。
###对象方法中的This
方法是关联在对象上的函数的别称, 如下: (注意: 这里的方法是ES6对象中定义方法的简写方式. 点击这里 如果你不确定它如何使用).
[JavaScript] 纯文本查看 复制代码
let o = {
// A method
aMethod () {}
}
任意方法中的this 指向对象本身。
[JavaScript] 纯文本查看 复制代码
let o = {
sayThis () {
console.log(this)
}
}
o.sayThis() // o
这里指向对象
既然 this 指向对象,你可以在方法中获得对象的实例,如下:
[JavaScript] 纯文本查看 复制代码
function Human (name) {
return {
name,
getName() {
return this.name
}
}
}
const zell = new Human('Zell')
const vincy = new Human('Vincy')
console.log(zell.getName()) // Zell
在接下来的两部分, 你可以看到this的值的改变使你可以获得正确的对象实例, 这是面向对象编程的基础。面向对象编程是接下来某天讨论的话题。
让我们介绍下面的部分
普通函数中的This大家熟知普通函数; 如下面的这个。以相同方式定义的匿名函数也被看做普通函数.
[JavaScript] 纯文本查看 复制代码
function hello () {
// say hello!
}
在浏览器中, 普通函数中this 总是被看做Window 对象。这在你调用对象中的方法的时候同样适用()。
[JavaScript] 纯文本查看 复制代码
function simpleFunction () {
console.log(this)
}
const o = {
sayThis () {
simpleFunction()
}
}
simpleFunction() // Window
o.sayThis() // Window
不幸的是, this的值在这里的改变是初学者不希望看到的。他们认为this 和对象方法中的是一致的。我也迷惑于此。
去了解原因,考虑下面的代码 ,this.speakLeet 方法在之后的setTimeout 函数中执行.
[JavaScript] 纯文本查看 复制代码
const o = {
doSomethingLater () {
setTimeout(function() {
this.speakLeet() // Error
}, 1000)
},
speakLeet() {
console.log(`1337 15 4W350M3`)
}
}
不幸的是,上述代码执行错误。错误的原因是在 setTimeout 函数中this 被设定为 Window对象 。Window 没有 speakLeet 方法。
解决方式是创建一个变量存储this的引用。这个变量通常叫做self 或 that。
[JavaScript] 纯文本查看 复制代码
const o = {
doSomethingLater () {
const self = this
setTimeout(function() {
self.speakLeet()
}, 1000)
},
speakLeet() {
console.log(`1337 15 4W350M3`)
}
}
第二种解决方式是使用ES6中的箭头函数,也就是我们下面要讨论的部分。
箭头函数中的This箭头函数中的this总是它定义时所指向的环境 (在它的定义环境)。 所以, 你在对象方法中使用箭头函数, this的执行环境总是指向对象, 而不是 Window。
上文中 speakLeet 可以在箭头函数中这样调用:
[JavaScript] 纯文本查看 复制代码
const o = {
doSomethingLater () {
setTimeout(() => this.speakLeet(), 1000)
},
speakLeet() {
console.log(`1337 15 4W350M3`)
}
}
第三种在任意函数内改变this值的方式是使用bind, call 或 apply方法。在下文中我们会介绍bind,下次介绍call 和 apply。但是首先我们先介绍最后一部分——事件监听器
事件监听器中的Thisthis被设定为事件监听器中绑定事件的对象:
[JavaScript] 纯文本查看 复制代码
let button = document.querySelector('button')
button.addEventListener('click', function() {
console.log(this) // button
})
当创建更复杂的组件时,您可能会发现自己在方法中创建事件监听器。
[JavaScript] 纯文本查看 复制代码
function LeetSpeaker (elem) {
return {
listenClick () {
elem.addEventListener('click', function () {
// Do something here
})
}
}
}
由于this 指的是事件监听器中的元素,如果需要调用另一个方法,则需要通过该方法所属对象进行调用。
[JavaScript] 纯文本查看 复制代码
function LeetSpeaker (elem) {
return {
listenClick () {
const self = this
elem.addEventListener('click', function () {
self.speakLeet()
})
},
speakLeet() { console.log(`1337 15 4W350M3`) }
}
}
你也可以使用箭头函数. 你可以通过 event.currentTarget来获得该元素的引用.
[JavaScript] 纯文本查看 复制代码
function LeetSpeaker (elem) {
return {
listenClick () {
elem.addEventListener('click', (e) => {
console.log(e.currentTarget) // elem
this.speakLeet()
})
},
speakLeet() { console.log(`1337 15 4W350M3`) }
}
}
这些匿名方法都不足以帮你移除事件监听器。
为了移除事件监听器,命名函数作为第二个参数:
[JavaScript] 纯文本查看 复制代码
function someFunction () {
console.log('do something')
// Removes the event listener.
document.removeEventListener('click', someFunction)
}
document.addEventListener('click', someFunction)
如果你需要在事件监听器中引用该对象, 你需要使用 bind手动创建this的执行环境.
[JavaScript] 纯文本查看 复制代码
function LeetSpeaker (elem) {[/size][/font][/color][/p]return {
listenClick () {
this.listener = this.speakLeet.bind(this)
elem.addEventListener('click', this.listener)
},
speakLeet(e) {
const elem = e.currentTarget
console.log(`1337 15 4W350M3`)
elem.removeEventListener('click', this.listener)
}
}
}
如果你没理解bind你可能对上述代码迷惑。所以,在解释为什么之前,先解释一下bind。
##通过bind改变this bind是一种在每个函数中都存在的方法。它允许你改变this上下文。此方法接受任意数量的参数并返回绑定函数。
[JavaScript] 纯文本查看 复制代码
const sayThis = _ => console.log(this)
const boundFunc = sayThis.bind(/* arguments...*/)
传入bind的第一个参数在绑定函数中变成this。创建了绑定函数后,可以随时调用它:
[JavaScript] 纯文本查看 复制代码
const sayThis = _ => console.log(this)
const boundFunc = sayThis.bind({hippy: 'hipster'})
boundFunc()
通过bind改变this
传递给bind 的其他参数将作为参数传递给原始函数。
[JavaScript] 纯文本查看 复制代码
const sayParams = (...args) => console.log(...args)
const boundFunc = sayParams.bind(null, 1, 2, 3, 4, 5)
boundFunc()
传递给bind的其他参数变成函数中的arguments
这就是你需要知道的关于bind的全部内容。
现在,让我们回顾一下移除事件监听器的代码,并剖析发生了什么:
[JavaScript] 纯文本查看 复制代码
function LeetSpeaker (elem) {
return {
listenClick () {
// Binds this.speakLeet with a reference to the instance.
// Sets bound function to this.listener, so we can remove it later.
this.listener = this.speakLeet.bind(this)
elem.addEventListener('click', this.listener)
},
speakLeet(e) {
console.log(`1337 15 4W350M3`)
// Gets the element so we can remove the event listener.
const elem = e.currentTarget
// Removes the event listener.
elem.removeEventListener('click', this.listener)
}
}
}
总结:
this是JavaScript中的关键词。它出现在许多JavaScript框架中,所以您必须知道它是做什么的。
在这篇文章中,您学习了六种不同的上下文,其中this具有不同的值。您还学会了如何用bind之类的函数来改变这个“上下文”。此外,您还学会了正确地删除事件侦听器。
这就是你需要知道的。只要掌握这篇文章所教的概念,你就不会再感到困惑了。