前言
对于js来说估计代码中用的最多就是this了,尤其是现在用了vue、react框架的项目,动不动就要this.xxx,但是很多时候我们只会照着用,如果需要分析一些特殊情况的this指向就有点吃力了,那么接下来就带大家一起总结一下不同情况下的this指向。
1.普通函数
console.log('1', this);//window
function a() {
console.log('2', this);//window
function b() {
console.log('3', this);//window
function c() {
console.log('4', this);//window
}
c();
}
let d = function () {
console.log('5', this);//window
}
b();
d();
}
a();
难道就这???
先来点简单的,一点点循序渐进
只要是通过function关键字注册在window下面的函数,可以进行直接执行的,this都指向window,这里与作用域无关,为什么指向都是指向window,因为这些函数都是注册在window顶级对象中的,调用的时候相当于window.a()、window.b()这样子,所以this理所应当指向window,可能这个总结的不是很好,往下看,在对象方法中有统一总结
2.事件处理函数
先上代码
<body>
<button id="btn">点我呀</button>
<script>
let btn = document.getElementById('btn');
btn.onclick = function () {
console.log('我被点击了');
console.log(this);//btn
}
function fn() {
console.log('我被双击了');
console.log(this);//btn
} btn.ondblclick = fn;
let myImg = new Image();
myImg.onload = function () {
console.log('我加载好了');
console.log(this);//myImg
}
myImg.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQoFWP4TyRgIFLd/1GFeEOK6OABACP7joDdno9VAAAAAElFTkSuQmCC';
</script>
</body>
在事件处理函数中,在谁身上触发的事件处理函数,函数中this就指向谁;
btn注册了点击事件处理函数,在btn身上触发了点击事件,所以函数中的this就指向btn;
像btn的双击事件这样,处理函数是后面引用上去的,也是一样(由于函数本来就是引用类型,所以当时注册和注册后再引用没区别,都是引用);
像myImg这样不是html中的获取来元素,自己创建的元素也是一样。
其实这种this指向也比较简单,就不再赘述。
3.对象的方法
先来看一段代码
let obj = {
name: '孙悟空',
skill: '七十二变',
sayHi: function () {
console.log('你好啊'); console.log('我叫' + this.name);//我叫孙悟空
console.log('我的技能是' + this.skill);//我的技能是七十二变
console.log(this);//obj
}
}
obj.sayHi();
记住样一句话:最后是谁调用的就指向谁
重中之重
接下来跟着我的步伐,一起来理解这句话吧
在sayHi方法调用时,因为是对象obj.(点)出来的,所以是obj在调用它,所以按照谁调用的就指向谁自然而然指向obj
这个同样适用于普通函数中,普通函数虽然省略了window直接写xxx(),但是它本义上是window.xxx(),是window在调用 所以就指向window
这个也同样适用于事件处理函数中,比如给div注册一个点击事件,div可以看做一个对象,注册事件其实是给div设置一个方法,之后这个对象调用这个方法执行,方法中的this指向这个对象,举个栗子
<body>
<button id="btn">点我呀</button>
<script>
let obj = { name: 'box' };
obj.onclick = function () {
console.log(this);//obj
console.log(obj.name);//box
}
obj.onclick();
</script>
</body>
上面是不是像极了给元素注册事件,最后的obj.onclick()只不过需要我们自己触发,其实元素的事件可以看做是浏览器内部帮我执行了xxx.onclick(),这样根据最后是谁调用的就指向谁,所以指向触发的事件处理函数的元素
再举一个例子巩固一下这个概念
function fn() {
console.log('你好啊');
console.log('我叫' + this.name);
console.log('我会' + this.skill);
}
let obj1 = {
name: '孙悟空',
skill: '七十二变',
sayHi: fn
}
let obj2 = {
name: '唐僧',
skill: '念经',
sayHi: fn
}
obj1.sayHi();
//你好啊
//我叫孙悟空
//我会七十二变
obj2.sayHi();
//你好啊
//我叫唐僧
//我会念经
this指向其实不是固定不变的,当同一个函数作为不同对象的方法时,函数里的this指向的是不同的对象,关键在于“谁调用”,所以请记住这句话最后是谁调用的就指向谁,
最后是谁调用的就指向谁,为什么要说是最后?
再来看一段代码
let obj1 = {
name: '孙悟空',
skill: '七十二变',
obj2: {
name: '唐僧',
skill: '念经',
sayHi: function () {
console.log(this);//obj2
console.log('我叫' + this.name);//我叫唐僧
console.log('我的技能是' + this.skill);//我的技能是念经
}
}
}
obj1.obj2.sayHi();
这个sayHi中的this指向是obj2,这个与它是.(点)了多少次点出来的无关,只看最后是谁在调用它就可以了
4.构造函数与类
1.先介绍一下构造函数的this指向,看代码
function Create1(a, b) {
this.name = a;
this.skill = b;
}
let obj = new Create1('哪吒', '喷火');
console.log(obj.name);//哪吒
console.log(obj.skill);//喷火
构造函数中的this指向的是即将被创造出来的对象
new关键字一共做了四件事情:
1.创建一个空对象
2**.将this指向这个对象**
3.执行构造函数中代码,完成对象的赋值
4.自动返回这个对象
这个应该比较好理解,生成实例对象的传统是通过构造函数,另外类也可以生成实例对象
2.下面再介绍一下类中this指向,看代码
class Create2 {
constructor(x, y) {
this.name = x;
this.skill = y;
}
fn1() {
console.log('我叫' + this.name);
console.log('我会' + this.skill);
}
fn2() {
console.log('这是一个寂寞的天');
console.log(this);
}
static fn3() {
console.log('下着有些伤心的雨');
console.log(this);
}
}
let obj1 = new Create2('孙悟空', '七十二变');
let obj2 = new Create2('唐僧', '念经');
obj1.fn1();
//我叫孙悟空
//我会七十二变
obj2.fn1();
//我叫孙悟空
//我会七十二变
obj1.fn2();
obj2.fn2();
Create2.prototype.fn2();
Create2.fn3();
类中三个地方的this指向,建议分开理解
可以把代码复制出来,自己运行一下试试
第一种:类中constructor构造器中的this指向
constructor相当于一个独立的构造函数,它的this指向和构造函数一样指向即将被创造出来的对象
第二种:类中的方法
类中的方法其实最后是添加到构造函数的原型对象上的,凡是类创造出来的对象包括原型对象本身都可以调用(如果不太理解可以了解下原型链的知识)
所以这里的this指向是不固定的,所以请按照前面重点强调的:最后是谁调用的就指向谁
第三种:类中的静态方法
也是按照最后是谁调用的就指向谁**,**类中的静态方法和普通方法区别是,静态方法在前面有static冠名,静态方法只能类自己访问到,所以自然而然它一般指向类它自己
感谢老铁的支持,已经把文章看到这里了
由于字数限制,请看下文