彻底理解JavaScript中this指向

JavaScript中this的指向

情况1: 如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。
情况2: 如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象.
情况3: this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的
情况4: 如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,这里需要说明的是在js的严格版中this指向的不是window,但是我们这里不探讨严格版的问题。
情况5: 匿名函数,定时器中的函数,由于没有默认的宿主对象,所以默认this指向window
情况6: 箭头函数没有自己的this, 它的this是继承而来; 默认指向在定义它时所处的对象(宿主对象),而不是执行时的对象, 定义它的时候,可能环境是window

详见代码,如下:

function a() {    
	var name = 'Tom'
	console.log(this.name); //undefined    (window下没有name这个属性)
	console.log(this);      //window 
}    
a();     //相当于window.a(),也就是window调用了a()方法,所以a方法中的this指向了window 


//情况1:
var b  = {
	say:{
		name: 'Tom',
		fn:function(){
			console.log(this.name);  //Tom  (say下有name这个属性)
		}
	}
};    
b.say.fn();  //fn方法中的this指向了say


//情况2:
var c  = {
	name: 'Tom',
	say:{
		fn:function(){
			console.log(this.name);  //undefined  (say下没有name这个属性)
		}
	}
};    
c.say.fn();	//fn方法中的this指向了say


//情况3:
var name = 'Jon'
var d  = {
	name: 'Tom',
	say:{
		fn:function(){
			console.log(this.name);  // Jon  (this指向window)
		}
	}
};    
var j = d.say.fn; //fn虽然被say引用,但是没有被执行调用,所以this不是指向的say,而是指向调用的j()方法的window
j()


//情况4:
var name = "The Window";  
var object = {    
    name: "The Object",
    getNameFunc: function () {      
        return function () {        
            return this.name;      
        };    
    }  
};  
alert(object.getNameFunc()());  //The Window
//匿名函数的自我执行,没有被上级对象调用,所以this指向window 


var name = "The Window";  
var object = {    
    name: "The Object",
    getNameFunc: function () {      
        var that = this;      
        return function () {        
            return that.name;      
        };    
    }  
};
alert(object.getNameFunc()());   //The Object
//在getNameFunc方法中将this绑定到that对象上,而that属于getNameFunc函数的内部变量,而这个函数的执行域是object。所以结果是"The Object"  


//情况5:
var obj = {
   say: function () {
     setTimeout(function () {
       console.log(this == window)
     });
   }
 }
 obj.say();
 //true


//情况6:
var obj = {
   say: function () {
     setTimeout(() => {
       console.log(this)
     });
   }
 }
 obj.say(); // this指向obj

构造函数中的this:

function Fn(){
    this.user = "bing";
}
var a = new Fn();    //new关键字可以改变this的指向,将这个this指向实例化对象a
console.log(a.user); //bing

为什么this会指向a?首先new关键字会创建一个空的对象,然后会自动调用一个函数apply方法,将this指向这个空对象,这样的话函数内部的this就会被这个空的对象替代。


如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。

function fn() {
    this.user = 'bing';
	return {user:'xia'};//返回的是对象  
}
var a = new fn;
console.log(a.user);    //xia


function fn() {
    this.user = 'bing';
	return function(){};//返回的是对象  
}
var a = new fn;
console.log(a.user);    //undefined


function fn() {
    this.user = 'bing';
	return false;      //返回的是布尔值 
}
var a = new fn;
console.log(a.user);   //bing


function fn() {
    this.user = 'bing';
	return 1;          //返回的是数字  
}
var a = new fn;
console.log(a.user);   //bing


function fn() {
    this.user = 'bing';
	return 'xia';     //返回的是字符串
}
var a = new fn;
console.log(a.user);  //bing


function fn() {
    this.user = 'bing';
	return undefined; //返回的是undefined 
}
var a = new fn;
console.log(a.user);  //bing


function fn() {
    this.user = 'bing';
	return null;      //返回的是null
}
var a = new fn;
console.log(a.user);  //bing

改变this指向

我们在js中可以使用document.write()方法向网页中输入文本内容。如

document.write("test"); 网页中就会被加入’test’文本。

但是如果我们像下面这么写呢?

var myWrite = document.write;
myWrite("test");  //报错

上面的代码首先是我将document.write方法赋值给myWrite方法。然后使用myWrite()方法向网页中输入文本内容。但是这里会报错,为什么呢?

原因就在这个write方法的this指针的域被改变啦!

document.write()方法的this是指向document的,所以可以向网页中输入文本内容。

但是我们将document.write方法赋值给myWrite对象,然后在调用myWrite()方法。调用myWrite()方法的对象域是全局变量window,相当于window.myWrite()。此时this指向window,而不指向document.所以会报错。

遇到上面的this指向被改变了,该怎么办呢?

这时候就要设置this的指针指向了,JavaScript有三个方法bind()、call()、apply()。

1.使用bind方法

a.bind(b); 就是将a()方法的this指针的作用域绑定到b对象的作用域上,也就是现在a的this指针的作用域就是b

如是上面的代码就可以改成:

var myWrite = document.write;  
myWrite.bind(document)("test"); //此时的this指针指向了bind()的document,网页中正常输出test。

2.使用call方法

call(a, b);: a是当前方法需要指向的域,后面的b是当前方法的参数,可以传多个参数,多个参数直接用逗号隔开即可,如 :call(a, b, c, d);, b, c, d都是方法的参数(arguments)。

var myWrite = document.write;  
myWrite.call(document, "test"); //此时的this指针指向了bind()的document,网页中正常输出test。   

3.使用apply方法

apply(a, b); :a是当前方法需要指向的域,后面的b是当前方法的参数,可以传多个参数,多个参数需要使用数组来传入。如apply(a, [b, c, d]);,b、c、d为参数(数组)。

var myWrite = document.write;  
myWrite.apply(document, "test"); //此时的this指针指向了bind()的document,网页中正常输出test。 

具体请看: JavaScript中call,apply,bind方法的总结

posted @ 2022-07-20 18:16  猫老板的豆  阅读(68)  评论(0编辑  收藏  举报