JS中this以及this的指向问题

72 阅读4分钟

this是什么

this就是函数运行时所在的对象(环境)。这本来并不会让用户糊涂,但是 JavaScript 支持运行环境动态切换,也就是说,this的指向是动态的,没有办法事先确定到底指向哪个对象,这才是最让初学者感到困惑的地方。

由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。

1、在全局作用域中 =>this -> window

<script>
   console.log(this); //this->window
</script>

2、在普通函数中 this取决于谁调用,谁调用函数,this就指向谁,跟如何定义无关

var obj = {
	fn1:function() {
	    console.log(this); 
	},
	fn2:function(){
	    fn3() 
	}
}
function fn3() {
    console.log(this); 
}
fn3();//this->window
obj.fn1();//this->obj
obj.fn2();//this->window

3、箭头函数中的this 箭头函数没有自己的this,箭头函数的this就是上下文中定义的this,因为箭头函数没有自己的this所以不能用做构造函数。

var div = document.querySelector('div'); 
var o={
	a:function(){
		var arr=[1];
		//就是定义所在对象中的this
		//这里的this—>o
		arr.forEach(item=>{
			//所以this -> o
			console.log(this);
		})
	},
    //o是定义在window中的对象,这里的this指向window
	b:()=>{
		console.log(this);
	},
	c:function() {
		console.log(this);
	}
}
div.addEventListener('click',item=>{
    //this->window 这里的this就是定义上文window环境中的this
	console.log(this);
});
o.a(); //this->o
o.b();//this->window
o.c();//this->o 普通函数谁调用就指向谁

4、事件绑定中的this 事件源.onclik = function(){ } //this -> 事件源

事件源.addEventListener(function(){ }) //this->事件源

var div = document.querySelector('div'); 

div.addEventListener('click',function() {
	console.log(this); //this->div
});
    
div.onclick = function() {
	console.log(this) //this->div
}

5、定时器中的this 定时器中的this->window,因为定时器中采用回调函数作为处理函数,而回调函数的this->window

setInterval(function() {
	console.log(this); //this->window 
},500)
    
setTimeout(function() {
	console.log(this); //this->window 
},500)

6、构造函数中的this

构造函数配合new使用, 而new关键字会将构造函数中的this指向实例化对象,所以构造函数中的this->实例化对象

new关键字会在内部发生什么

//第一行,创建一个空对象obj。
var obj  ={};
//第二行,将这个空对象的__proto__成员指向了构造函数对象的prototype成员对象.
obj.__proto__ = CO.prototype;
//第三行,将构造函数的作用域赋给新对象,因此CA函数中的this指向新对象obj,然后再调用CO函数。于是我们就给obj对象赋值了一个成员变量p,这个成员变量的值是” I’min constructed object”。
CO.call(obj);
//第四行,返回新对象obj。
return obj;
function Person(name,age) {
        this.name = name;
        this.age = age;
    }
var person1 = new Person();
person1.name = 'andy';
person1.age = 18;
console.log(person1);	//Person {name: "andy", age: 18}
var person2 = new Person();
person2.name = 'huni';
person2.age = 20;
console.log(person2);	// Person {name: "huni", age: 20

7、对象方法调用中,this指向对象

// 实例1
const obj = {
	name: "bwf",
	age: 18,
	eat: function() {
	    console.log(this); //{name: "bwf", age: 18, eat: ƒ}
		console.log(this.name + "正在吃饭"); //bwf正在吃饭
    }
}
obj.eat();

// 实例2
function foo() {
        console.log(this.a);
    }
    var obj2 = {
        a: 2,
        fn: foo
    };
    var obj1 = {
        a: 1,
        o1: obj2
    };
obj1.o1.fn(); // 2  fn最终是在obj2的环境中被调用的,所以结果是2

// 实例3
var o = {
	a: 10,
    b: {
        // a:12,
        fn: function() {
            console.log(this.a); //undefined fn是在b的环境中被调用的
        }
    }
}
o.b.fn();
  • 如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,
  • 如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象
var o = {
    a: 10,
    b: {
        a: 12,
        fn: function() {
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
}
var j = o.b.fn;
j();
// 上面例子中,虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window

总结:

  • 当函数作为对象的方法被调用时,this 指向该对象。
  • 当函数作为普通函数被调用时,this 指向全局对象(在浏览器中是 window 对象)。
  • 当函数作为构造函数被调用时,this 指向新创建的对象。
  • 当使用 apply() 或 call() 方法调用函数时,this 可以被显式指定为任何对象。
  • 当使用箭头函数时,this 的指向是在定义函数时确定的,指向的是箭头函数所在的上下文。

需要注意的是,this 的指向是动态的,取决于函数的调用方式,在不同的上下文中,this 可能会指向不同的对象。因此,在编写代码时,需要注意函数是如何被调用的,以确保正确使用 this 关键字。