不同场景下的this指向问题
window
在js文件中直接打印this
console.log(this); // window
浏览器中如下:
对象
1、首先创建一个平平无奇 对象,在方法中打印this:
const obj = {
name: 'wang',
age: 18,
play: 'pingpang',
baseInfo: function() {
console.log(this); // obj对象
console.log(this.name + '的年龄是' + this.age ); // wang的年龄是18
}
}
obj.baseInfo()
浏览器打印如下:
因此:调用对象的方法,this指向对象本身
2、下一步,我们改造上面obj,改变[‘play’]的值,并创造 一个新属性
const obj = {
name: 'wang',
age: 18,
play: 'pingpang',
likes: function() {
this.play = 'basketball'
console.log(this); // 更改后的 obj对象
this.likeType = '有氧'
console.log(this.name + ' like ' + this.play +'。并喜爱' + this.likeType); // wang like basketball。并喜爱有氧
}
}
obj.likes()
打印如下:
因此,this指向对象时,改变原有对象的key值,或创建一个新的key,此时this指向被改变之后的对象
3、上面我们测试了对象中的普通函数,如果换成 箭头函数 呢?继续改造obj:
const obj = {
name: 'wang',
age: 18,
play: 'pingpang',
test: () => {
console.log(this); // window 对象
this.testA = '语文'
console.log(this.name + ' 喜欢的课程是' + this.testA); // 喜欢的课程是语文
}
}
obj.test()
打印如下:
因此:调用对象的箭头函数方法,this的指向是window,不能再如第二步改变 play 的值一样改变 name,所以上面打印不是 “wang喜欢的课程是语文” 而是 “喜欢的课程是语文”。
4、如果我们进一步改造obj的方法,测试下在setTimeout里的this指向呢?
const obj = {
name: 'wang',
age: 18,
play: 'pingpang',
testSetTimeout: function() {
setTimeout(function() {
console.log('setTimeout(function(){})=======', this) // window
console.log(this.play)
},5)
setTimeout(() => {
console.log('setTimeout(()=>{})=======', this) // obj
console.log(this.play)
},10)
}
}
obj.testSetTimeout()
打印如下:
这里的结果似乎有些出乎意料~
调用对象的方法:
setTimeout里回调是普通函数时,this的指向是window
setTimeout里回调是箭头函数时,this的指向是对象本身
函数
创建一个普通函数
function testFunc(){
console.log(this);
this.num1 = 20;
console.log('this.num1: ', this.num1); // 20
}
// 调用1
testFunc() // window
// 调用2
let test2 = testFunc()
test2() // window
打印如下:
因此,在普通函数中,this指向window
类
1、创建一个类
class fatherObj {
constructor(name, age){
this.name = name
this.age = age
}
showText(){
console.log(this) // fatherObj
return '姓名是:' + this.name + ',年龄是:' + this.age
}
}
const fatherObj_C = new fatherObj('wang', 18)
console.log(fatherObj_C.showText()) // 姓名是:wang,年龄是:18
打印如下:
因此,在类里使用this,this指向类本身
2、进一步改变类的方法 showText,我们来改变name的值来查看变化
class fatherObj {
constructor(name, age){
this.name = name
this.age = age
}
showText(){
this.name = '小王'
console.log(this) // 新fatherObj
return '姓名是:' + this.name + ',年龄是:' + this.age
}
}
const fatherObj_C = new fatherObj('wang', 18)
console.log(fatherObj_C.showText()) // 姓名是:小王,年龄是:18
打印如下:
由此可见,this指向的是更新之后的类
3、保留第2步的fatherObj类,我们进一步测试,创建它的子类
class sonObj extends fatherObj {
constructor(name, age, sex){
super(name, age)
this.sex = sex
}
showMore(){
console.log(this)
return super.showText()+' ,性别是:' + this.sex
}
}
const son_C = new sonObj("xiaowang", 5, 'nv')
console.log('son_C: ', son_C.showMore());
打印如下:
因此,在类里,this始终指向的是类本身。也很清晰看到,子类sonObj的原型上是父类fatherObj
改变this的指向
前置代码,先码个对象和函数吧~
const testFunc = function(params1, params2) {
console.log(this)
console.log('params1: ', params1);
console.log('params2: ', params2);
return {name: 'wang'}
}
const testObj = {
p1: 11,
p2: 22,
showThis(params){
console.log('showThis=====', this, params)
}
}
如果我们调用testFunc()
和 testObj.showThis()
,this的指向应分别是 window
和 testObj
吧。
下面,我们来看看改变this的指向~
call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象
call
1、改变testFunc的this指向:
testFunc.call(testObj, 3,4)
// {p1: 11, p2: 22, showThis: ƒ}
// params1: 3
// params2: 4
testFunc.call(testObj, 'test2')
// {p1: 11, p2: 22, showThis: ƒ}
// params1: test2
// params2: undefined
testFunc.call(testObj)
// {p1: 11, p2: 22, showThis: ƒ}
// params1: undefined
// params2: undefined
testFunc.call()
// window
// params1: undefined
// params2: undefined
testFunc.call(null)
// window
// params1: undefined
// params2: undefined
testFunc.call(undefined)
// window
// params1: undefined
// params2: undefined
testFunc.call(2)
// Number{2}
// params1: undefined
// params2: undefined
2、改变testObj的指向
testObj.showThis.call(testFunc())
// Window {…}
// params1: undefined
// params2: undefined
// showThis===== {name: 'wang'} undefined
testObj.showThis.call(testFunc(), 18)
// showThis===== {name: 'wang'} 18
apply
apply 和 call 的区别在于,apply的参数要放在数组里传过去,call的参数直接放进去
testFunc.apply(testObj, [1,2])
// {p1: 11, p2: 22, showThis: ƒ}
// params1: 1
// params2: 2
testFunc.apply([1,2])
// [1, 2]
// params1: undefined
// params2: undefined
testFunc.apply(undefined)
// Window {…}
// params1: undefined
// params2: undefined
bind
bind 除了返回是函数需要自调用外,它的参数和 call 一样。
testFunc.bind(testObj, 3, 4)()
// {p1: 11, p2: 22, showThis: ƒ}
// params1: 3
// params2: 4
参考文章:
1、this的指向
2、call、apply、bind的用法