this的指向是javascript种一个老生常谈的问题,今天我以一个项目实践来谈谈this在工作中的使用。
基础知识
我们知道,this对象是在运行时基于函数的执行环境绑定的:在全局作用域中this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。
工作中遇到的问题
下面我们在这样的一个环境里面来判断this的指向
class Page {
constructor() {
Hybrid('customNavBarRightBtn').customNavBarRightBtn({
//默认隐藏右上角分享按钮
hidden: true
})
this.$activity = $('#activity')
this.bindEvents()
getData()
.then(res => {
this.res = res
this.albums = [res.albums.slice(0, 3), res.albums.slice(3, 6)]
this.res.albums = this.albums[0]
this.$activity.html(tpl.render(this.res))
})
.catch(err => {
popup.note(err.message || err.err_msg || JSON.stringify(err))
})
}
}
new Page()
class是es6中的一个语法糖,关于它的详细介绍请参看阮一峰《ES6标准入门》
在上面这段代码中,this全部都指向Page的实例,我之所以要用this来储存变量是为了下面一段代码
class Page {
constructor() {
...
...
...
}
bindEvents() {
let _this = this
this.$activity.on('click', '.changMusic', function() {
if (_this.res.albums === _this.albums[0]) {
_this.res.albums = _this.albums[1]
} else {
_this.res.albums = _this.albums[0]
}
_this.$activity.html(tpl.render(_this.res))
})
}
}
new Page()
这里我使用_this来江this保存起来,是因为在点击事件的作用域里,this是指向绑定的点击的div的,但是我希望this指向class的实例。这里除了将this存起来以外,还有其他的方法。这里我介绍两种:
- 使用ES6箭头函数。我们知道,在ES5中,this指向的是执行时的作用域,而在ES6this指向定义时的作用域。所以使用箭头函数,thiss的作用域就变成class的实例了。但是这样做有一个问题,如果我们想使用$(this)来对点击事件进行操作,那就不行了,因为在箭头函数中无法使用call()或apply()方法。为什么不能使用呢?因为箭头函数里根本没有自己的this,导致内部的this就是外部代码块的this。因为它没有this,所以他也不能作为构造函数。
- 使用call或apply()改变this指向。
this在什么时候使用
其实如果我们定义的一个变量,只需要在某一个函数中使用,是不需要用到this的。但是有时候我们希望函数内的变量在函数外也还能用,就可以用this了。特别是在使用es6的class的时候,我们可以要在整个class中用到的变量放在constructor中,这样在class下面的函数中都可以对变量进行操作了。