首先引入MDN中对this的解释:
在绝大多数情况下,函数的调用方式决定了
this
的值(运行时绑定)。this
不能在执行期间被赋值,并且在每次函数被调用时this
的值也可能会不同。ES5 引入了 bind 方法来设置函数的this
值,而不用考虑函数如何被调用的。ES2015 引入了箭头函数,箭头函数不提供自身的 this 绑定(this
的值将保持为闭合词法上下文的值)
1)this是一个对象,表示为当前代码的执行环境
2)this的值取决由ta所处的环境决定:
- 在全局环境中,this的值总是Window
- 在函数环境中,this的值取决于函数的调用方式(下面会讲到)
3)this的值可以改变,可以使用call、apply、bind 方法设置this的值
下文主要讨论this的值(this的指向)问题
1、全局执行环境
全局上下文默认this指向window,严格模式下指向undefined。
// 在全局环境中打印this:
console.log(this) // => Window
2、直接调用函数
这种情况是直接调用,this相当于全局执行环境的情况。
// 在全局中定义的函数:
function _this() {
console.log(this)
}
// 直接调用函数的方式
_this() // => Window
立即执行函数也是一样的情况。
3、对象.方法的形式调用
这种情况调用时,this就是ta的调用者
let obj = {
name: 'zs',
say() { // es6语法
console.log(this)
}
}
// 对象.方法的方式
obj.say() // => { name: 'zs', say: f } 即为上面定义的 obj
类似的 window.setTimeout(fn, 1000) 也是相同情况。
4.、DOM事件绑定
this就是dom事件绑定的元素
// 定义一个html元素
<input type="button" value="点击" id="btn">
<script>
let btn = document.querySelector('#btn') // 获取元素
btn.addEventListener('click', function () { // 绑定事件
console.log(this) // => <input type="button" value="点击" id="btn">
})
</script>
5、new+构造函数
此时构造函数中的this值为其实例对象。
function Person(name) { // 构造函数Person
this.name = name // this为new创建出来的新对象,this.name就是为新创建的对象添加name属性。
// 这就是为什么在构造函数中用this.xx来创建属性
}
let zs = new Person('zs') // Person的实例对象
console.log(zs) // => Person {name: "zs"}
6、 箭头函数?
在箭头函数中,this
与封闭词法环境的this
保持一致。this的值为当前最近的非箭头函数的this
// 全局环境
let fn = () => {
console.log(this) // => Window
}
fn()
// 对象
let obj = {
do: () => {
console.log(this) // => Window
},
go: function () {
console.log(this) // => obj
let child = () => {
console.log(this) // => obj
//child为go函数中定义的箭头函数,因为箭头函数没有this,故child继承go函数中的this
}
child()
}
}
obj.go()