this指向解析
几个月以前就想要写一些博客,记录自己的学习历程,但由于各种原因,没能动工,2019的第一个月即将过去,今天终于下定决心抓住一月的尾巴,勤奋一把,激励自己在2019能有所收获。所以这第一篇,就从面试常见的考点this指向开始吧。
总的来说,我们始终要牢记的一句话就是:this始终指向最终调用它的那个对象
1.直接作为一个函数被调用,this指向window
function demo () {
var a = '这是第一个demo的a'
console.log(this)
console.log(this.a)
}
demo()
// window
// undefined
为什么此处this.a是undefined呢?因为我们可以把demo看成window.demo,window对象并没有a这个属性,所以是undefined。如果希望打印出'这是第一个demo',可以将代码改为如下示例:
function demoUpdate () {
this.a = '这是第一个demo的a'
console.log(this)
console.log(this.a)
}
demoUpdate()
// window
// 这是第一个demo的a
2.作为对象的方法被调用,this指向这个对象
var obj = {
a: '这是第二个demo的a',
func: function () {
console.log(this)
console.log(this.a)
}
}
obj.func()
// 指向obj
// 这是第二个demo
3.作为构造函数被调用,this指向这个构造函数的实例对象
function Constructor () {
var a = '这是第三个demo的a'
this.a = '这是第三个demo的b'
console.log(this)
console.log(this.a)
}
var func = new Constructor()
// 指向Constructor的实例对象
// 这是第三个demo的b
为什么此处的this.a指向的却是'这是第三个demo的b',而不是a呢?这就涉及到构造函数的继承问题了,这里用var a 声明的a在Constructor的实例对象,也就是func中实际上并不存在,只有this.a声明的这个a对象才被func对象继承,存在于func中,所以当打印this.a时,打印的就是'这是第三个demo的b'
4.如果一个函数中有this,且这个函数中包含多个对象,this指向它的上一级对象,即最后调用它的那个对象
var obj = {
a: '这是第四个demo的外层a',
child: {
a: '这是第四个demo的内层a',
func: function () {
console.log(this)
console.log(this.a)
}
}
}
obj.child.func()
// 指向obj.child
// 这是第四个demo的内层a
5.如果遇到return,若return的是一个对象,则this指向这个对象,若return的不是对象,则仍然指向这个函数的实例(null例外,虽然null是一个对象,但仍然指向对象的实例)
function Constructor () {
this.a = '这是第五个demo的a'
return {}
}
var b = new Constructor
console.log(b.a) //undefined
因为此时b指向的是Constructor生成的实例对象,而这个对象是个空对象,没有a属性
function Constructor () {
this.a = '这是第六个demo的a'
return function () {}
}
var b = new Constructor
console.log(b.a) // undefined,此时b指向的是Constructor的新的实例对象,也就是function () {}
再看return的不是对象的情况
function Constructor () {
this.a = '这是第七个demo的a'
return 1
}
var b = new Constuctor
console.log(b.a) // 这是第七个demo的a
此时b指向的是新生成的Constructor的实例对象,这个实例对象的a属性即为:这是第七个demo的a
function Constructor () {
this.a = '这是第八个demo的a'
return undefined
}
var b = new Constructor
console.log(b.a) // 这是第八个demo的a,理由同上
function Constructor () {
this.a = '这是第九个demo的a'
return null
}
var b = new Constructor
console.log(b.a) // 这是第九个demo的a
改变this的指向
首先看一个没有改变this指向时的例子
var obj = {
a: '这是第十个demo的a',
func1: function () {
console.log(this.a)
},
func2: function () {
setTimeout( function () {
this.func1()
}, 1000)
}
}
obj.func2() // this.func1 is not a function
为什么此处报错而没有打印‘这是第十个demo的a’呢?因为当调用obj.func2时,func2中的setTimeout函数实质上是调用window对象的setTimeout函数,this指向window,而window对象没有func1这个属性,所以报错
1.使用箭头函数改变this的指向
箭头函数中没有this绑定,必须通过作用域链决定this的值,如果箭头函数被非箭头函数包含,则this指向最近的一层非箭头函数的this,否则,this为undefined
var obj = {
a: '这是第十一个demo的a',
func1: function () {
console.log(this.a)
},
func2: function () {
setTimeout(() => {
this.func1()
}, 1000)
}
}
obj.func2() // 这是第十一个demo的a
2.在函数内部使用that = this改变this的指向
var obj = {
a: '这是第十二个demo的a',
func1: function () {
console.log(this.a)
},
func2: function () {
var that = this
setTimeout(function() {
that.func1()
}, 1000)
}
}
obj.func2() // 这是第十二个demo的a
3.使用call,apply, bind改变this的指向
首先区分这三个函数的区别: call和apply改变this的指向后立即执行,而bind仅绑定this的指向,并不立即执行,返回改变this指向后的函数
call和bind的参数可以有多个,第一个参数为绑定的this的指向,后面的参数为传入函数的参数
apply只有两个参数,第一个参数为绑定的this的指向,第二个参数为包含传入函数的参数的数组
以上内容为我自己记录的知识点,如果后面有补充的,我会继续添加,此博客仅做记录知识点使用,若有幸被大佬们指点,不对的还烦请指正。