不同场景下的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) // windowconsole.log(this.play)},5)setTimeout(() => {console.log('setTimeout(()=>{})=======', this) // objconsole.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}// 调用1testFunc() // window// 调用2let test2 = testFunc()test2() // window
打印如下:
因此,在普通函数中,this指向window
类
1、创建一个类
class fatherObj {constructor(name, age){this.name = namethis.age = age}showText(){console.log(this) // fatherObjreturn '姓名是:' + 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 = namethis.age = age}showText(){this.name = '小王'console.log(this) // 新fatherObjreturn '姓名是:' + 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: 4testFunc.call(testObj, 'test2')// {p1: 11, p2: 22, showThis: ƒ}// params1: test2// params2: undefinedtestFunc.call(testObj)// {p1: 11, p2: 22, showThis: ƒ}// params1: undefined// params2: undefinedtestFunc.call() // window// params1: undefined// params2: undefinedtestFunc.call(null)// window// params1: undefined// params2: undefinedtestFunc.call(undefined) // window// params1: undefined// params2: undefinedtestFunc.call(2) // Number{2}// params1: undefined// params2: undefined
2、改变testObj的指向
testObj.showThis.call(testFunc())// Window {…}// params1: undefined// params2: undefined// showThis===== {name: 'wang'} undefinedtestObj.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: 2testFunc.apply([1,2])// [1, 2]// params1: undefined// params2: undefinedtestFunc.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的用法