对于this,理解一直都不透彻,前前后后也看了一些技术书,以后相关博客,总算是想要总结点什么了。
this在不同的上下文环境指代不同的对象,与声明环境无关,与运行环境有关
- this 指向全局对象window(在服务器端指向global)
var name = 'jack'
function sayName () {
console.log(this.name)
}
sayName() // jack
- this 指向当前的调用对象
// 第一种情况,作为对象方法的调用
function sayName () {
console.log(this.name)
}
var o = {}
o.name = 'jack'
o.sayName = sayName
o.sayName() // jack
// 第二种情况作为构造函数调用时,this指向新创建的对象
1. 简单的场景
function Test () {
this.x = 1
}
var o = new Test()
o.x //1
2. 为表明this不是全局对象,做一下修改
var x = 0
function Test () {
this.x = 1
}
var o = new Test()
o.x // 1
3. 稍微复杂的场景
function Person(name){
this.name = name
}
person.prototype.sayName = function () {
console.log(this.name)
}
var xiaoming = new Person('xiaoming')
xioaming.sayName() // xiaoming
- 使用apply 或 call 来进行绑定 apply或call 是调用函数的方法,他们第一个参数都相同,用于指定当前函数的调用对象
var name = 'rose'
function sayName () {
console.log(this.name)
}
var o = {}
o.name = 'jack'
o.sayName = sayName
o.sayName.apply() //输出rose 没有指定绑定对象,默认指向全局对象
o.sayName.apply(o) //输出 jack 此时this代表对象o
疑难this辨析
// 下面的this指代什么
var name = "Bob";
var nameObj ={
name : "Tom",
showName : function(){
alert(this.name);
},
waitShowName : function(){
setTimeout(this.showName, 1000);
}
};
nameObj.waitShowName(); // Bob
为了解决以上问题,我们可以先一步一步看以下this的指向
var person = {
name: 'jack',
sayName: function () {
console.log(this.name)
}
}
var anotherPerson = {
name: 'rose',
sayName: person.sayName
}
anotherPerson.sayName() // rose
// this关键字虽然是person.sayName种声明的,但是运行的时候是在anotherPerson.sayName,所以this指向anotherPerson,输出rose
var name = 'jack'
var o = {
name: 'rose',
sayName: function () {
console.log(this.name)
}
}
var sayName = o.sayName
sayName() // jack
// 此时可以理解为,sayName()是在全局作用域下执行的,所有this指向window,window.name === 'jack'
var name = 'willie'
var Jack = {
name: 'jack',
sayName: function () {
console.log(this.name)
}
}
var Rose = {
name: 'rose',
sayName: function () {
var fun = Jack.sayName
fun()
}
}
Rose.sayName() // willie
// 这次情况跟上次不同的是,是在函数内部引用了其他的函数,此时的this由于没有绑定Rose,所以指向默认的绑定window
在浏览器中,setTimeout, setInterval,匿名函数执行时的当前对象都是全局对象window
var name = 'wille'
var o = {
name: 'jack',
sayName: function () {
setTimeout(function () {console.log(this.name)}, 100)
}
}
o.sayName() // wille
// 使用ES6的箭头函数改写上述代码,观察会产生什么情况
var name = 'wille'
var o = {
name: 'jack',
sayName: function () {
setTimeout(() => {console.log(this.na)},100)
}
}
o.sayName() //jack
// 记住在setTimeout,setInterval,匿名函数中,如果使用箭头函数改写,this指向当前上下文环境,而不是全局对象。
思考题, 思考下列this指向什么,以及原因
1:
var obj = {
say: function () {
setTimeout(() => {
console.log(this)
}, 0)
}
}
obj.say() //obj
2:
function test() {
console.log(this)
}
test() // window(全局)
3:
var obj = {
say: function () {
function _say () {
console.log(this)
}
return _say.bind(obj)
}() //立即执行函数,此时obj还没有声明出来,故this还是默认的window
}
obj.say() // window(全局)
4:
var obj = {}
obj.say = function () {
function _say () {
console.log(this)
}
return _say.bind(obj)
}() // 立即执行函数,这次obj已经声明了出来,此时的this指向obj
obj.say() // obj
5:
var obj = {
sayName: function () {
console.log('outer', this)
return function () {
console.log('inner', this)
}
}()
}
//匿名函数立即执行,this指向window,返回了一个匿名函数的声明
//此时内部的匿名函数没有执行,所以this不会指向全局window
obj.sayName() //outer -> window inner -> obj
// 而在真正执行时,此时的obj.sayName()中的this指向了调用对象obj
// 以上obj声明的等价形式为
var obj = {
sayName : function () {
console.log('inner', this)
}
}
obj.sayName() // obj
// 此时应该可以一眼看出,当通过obj调用sayName时,this指向当前调用对象obj