概述
this主要分为以下几种
- 非严格模式下,全局中this指向window
- 对象中的this : 属性中的this指向外层this ;方法中的this指向该对象
- 回调函数中的this指向window
- 事件回调函数中的this被修改成e.currentTarget(被侦听的对象)
- 箭头函数中的this指向指当前函数外
- ES6类中的this指向实例化对象 ,静态方法或者属性指向该类名
- ES5中的类中的this 原型上的属性和方法指向实例化对象,静态指向类名
- call apply bind 的this指向第一个参数
1-----全局中this指向window
非严格模式下,下面的this都是window
console.log(this);//window
function abc(){
console.log(this);//window
}
2-----对象中的this
- 对象中属性的this,指的是外层的this,因为这时候对象还没有创建完成
- 对象中的方法是在对象执行完成以后才调用的.所以this就是当前对象
var a=10;
var obj1={
a:100,
c:this.a,//10 this是window 这时候对象还没有创建完成,指向外层的this,即为window
init:function(){
// this
var obj={
a:1,
c:this.a,// 100 属性描述this是obj1
b:function(){
console.log(this.a);//1 方法中使用this,指向该对象obj
}
}
obj.b();
console.log(obj.c)//100
}
}
obj1.init();
var obj = {
a: 1,
c: this.a,//属性描述this为window
b: function () {
// 方法中使用this
console.log(this.a); //1 this为obj
this.d();//this为obj
// obj.d();//不能写出obj.d();因为obj可能会更改
},
d:function(){
console.log("aaa");
}
}
obj.b();
3-------回调函数中的this指向window
function a(fn){
fn();
}
function abc(){
console.log(this);//window 这个函数是回调函数
}
a(abc);
var obj={
a:function(){
console.log(this);//obj
var arr=[1,2,3];
arr.forEach(function(){
console.log(this);//window 这个forEach中的函数是回调函数
})
this.b(this.c);
this.b(abc);
},
b:function(fn){
fn();
console.log(this,"_____");//对象中的方法中的this指向该对象 obj
},
c:function(){
console.log(this);//window 这个函数是回调函数
}
}
obj.a();
var obj={
a:function(fn){
fn();
},
b:function(){
// 如果直接执行obj.b() 这里的this应该是obj对象
// 如果通过上面a方法回调执行当前b的时候,this被重定向到window
console.log(this);
}
}
obj.a(obj.b);
所有的函数一旦被写在一个方法中,这个函数就是匿名的回调函数,在该函数中this指向window…比如:forEach()、filter()、reduce()、map()、some()、every()、promise…中函数都是回调函数,它们的 this 也都指向 window。
var obj = {
a: function () {
setTimeout(function () {
console.log(this)//window
}, 100);
// 所有的函数一旦被写在一个方法中,这个函数就是匿名的回调函数,在该函数中this指向window
setInterval(function(){
console.log(this);
},100)
var arr=[1,2,3];
arr.map(function(){
console.log(this);//window
// forEach,filter,reduce,some,every,flatMap
});
new Promise(function(resolve,reject){
console.log(this);//window
})
}
}
4------事件回调函数中的this被修改成e.currentTarget(被侦听的对象)
// 事件侦听
document.addEventListener("click",clickHandler);
// 事件回调函数
function clickHandler(e){
console.log(this)// 事件回调函数中this都是被侦听的对象 this--->e.currentTarget
}
对象中的事件函数
第一次打印obj 点击打印document
var obj={
a:function(){
document.addEventListener("click",this.b);
this.b();//对象里方法中的this为该对象obj
},
b:function(e){
// 因为b函数是事件侦听的回调函数,因此这里this指向事件侦听的对象,也就是document
console.log(this);
}
}
obj.a();
5-----箭头函数中的this
- 所有箭头函数内的this都是指当前函数外的this指向
- 当箭头函数和回调函数一起时,箭头函数改变了this指向,将指向箭头函数外层的this
var obj={
a:function(){
var arr=[1,2,3];
arr.forEach(function(){
console.log(this);//遵从于回调函数的this指向。window
// this.d();//报错,window中没有方法d
});
arr.forEach(item=>{
console.log(this)//obj
// this 因为使用了箭头函数,就会忽略了回调函数的this指向
})
document.addEventListener("click",this.clickHandler);
document.addEventListener("click",e=>{
console.log(this)//obj
// this 因为使用箭头函数,就会忽略了事件函数中this指向
this.d();
})
},
clickHandler:function(e){
console.log(this)//遵从于事件函数中this---e.currentTarget
// this.d();//报错 this为document事件对象
},
d:function(){
console.log(this)
},
e:function(){
setTimeout(()=>{
// 因为本来是回调函数,this统一都会被指向window
// 但是使用了箭头函数,就会全部把这里this指向setTimeout外的this指向,也就是obj
console.log(this);
},100)
}
}
obj.a();
6------ES6类中的this指向实例化对象 ,静态方法或者属性指向该类名
- 类中的this是指实例化的对象,谁调用的属性和方法,this就是谁
- 静态属性或者方法,this指向都会被设置为当前的类名Box(对于面向对象语言来说,一般在静态属性和方法中不允许使用this这个概念)
- 如果类被继承,继承后静态方法也会被继承
class Box{
// ES7后才有的
// 这里的内容是constructor执行后赋值
b=3;
// a=this.b;
static b=20;
/static a=this.b;
//一旦被设为静态属性,this指向都会被设置为当前的类名Box 因为设置了static b=20 所以a是20
constructor(){
this.b=3;
this.a=this.b;
//Box.b=20;
//Box.a=Box.b;早期的静态属性写法,相当于static
}
play(){
// 这里的this都是实例化的对象
console.log(this.a);
}
static run(){
console.log(this);
// this
// 因为使用static定义的方法,this指向为当前类名Box
// 对于面向对象语言来说,一般在静态属性和方法中不允许使用this这个概念
}
}
var b=new Box();
如果类被继承,继承后静态方法也会被继承
//Ball继承Box
class Ball extends Box{
constructor(){
super();
}
}
var b=new Ball();
Ball.run();//继承后静态方法也会被继承
案例
export default class Rect{
elem;
bool=false;
speed=2;
x=0;
constructor(){
this.elem=this.creatElement()//this指向该类,调用该类的方法直接用this
}
//创建元素
creatElement(){
if(this.elem) return this.elem;
let div= document.createElement('div')
Object.assign(div.style,{
width:'50px',
height:'50px',
background:'red',
position:"absolute",
left:"0px"
})
div.addEventListener('click',e=>this.clickHandler(e))
//事件回调函数中this是该事件,这里需要调用该类中的方法clickHandler(),所以需要用箭头函数改变this指向为该类
return div
}
//添加到父元素
appendElem(parent){
parent.appendChild(this.elem)
}
//添加点击事件
clickHandler(e){
this.bool=!this.bool;//使用类中的属性,直接用this.属性就可以
}
//移动
move(){
if(!this.bool) return;
this.x+=this.speed;
console.log(this.x)
this.elem.style.left=this.x+'px'
}
}
7----ES5中的类 原型上的属性和方法指向实例化对象,静态指向类名
- ES5中没有类,借用原型的概念实现类
- 静态方法只和类有关系,与实例化的对象没有任何关系
- b对象没有play这个对象属性,因此就去原型链中找到最近的play方法
function Box(){
//相当于es6中的constructor()
this.play();
// 构造函数中this,new出的对象-->b
}
Box.a=function(){
// 这个方法类似于ES6的静态方法
// this -->Box
}
Box.b=3;//和ES6静态定义属性一样
Box.prototype.play=function(){
// this 就是当前调用该方法的实例对象 -->b
}
Box.prototype.c=10;
console.log(Box.b)//3 获取静态属性b
var b=new Box();
b.play();//b对象没有play这个对象属性,因此就去原型链中找到最近的play方法,执行这个play方法是由b这个对象执行,因此play中的this就是b
如下图 b.proto 等同于Box.prototype
8----call apply bind 的this指向第一个参数
- 当使用call,apply,bind都会将函数中this的指向重新指向到对应的对象
- call 执行函数,并且将该函数中this指向call的第一个参数,call的第二个参数开始一一带入所有参数
- apply 执行函数,并且将该函数中this指向call的第一个参数,apply的第二个参数是这个函数的所有参数组成数组
- bind执行函数,并且将函数中的this指向bind的第一个参数
- 当第一个参数为空或者null时,this指向window
function fn(_a,_b){
this.a=_a;//this指obj
this.b=_b;
}
var obj={};
//fn.call(obj,3,5);
fn.apply(obj,[3,5]);
console.log(obj);//{a:3,b:20}
bind
function fn1(fn){
fn(3);
}
function fn2(_a){
this.a=_a;//this是指obj
}
var obj={};
fn1(fn2.bind(obj));//把fn2函数中的this指向obj,并且返回这个被指向this后新的函数
console.log(obj);//{a:3}