深入理解this的指向问题,在代码中灵活使用this对象

今天是准备面试的第八天,那我们就讲一讲我们在代码中经常遇到的this关键字吧。
最重要的概念:this在函数定义的时候确定不了,只有在函数执行,this指向调用它的对象
你把这句话理解了,你就初步懂this的指向了

一、this指向的分类

我将其分为四类

  • 函数调用模式
  • 方法调用模式
  • 构造函数调用模式
  • cell,apply,bind重指向模式

是不是感觉有点晕呀!别忙我们一个一个来讲解

二、解说this的指向

1.函数调用模式

当一个函数不是一个对象的属性时,当它被当做一个函数来调用,this绑定为全局对象,及最外层的环境windows。

function fn(){
	var a = 'hello';
	console.log(this.a);//undefined
	console.log(this);//window
}
fn();

这里的this指向的是window

2.方法调用模式

当一个函数是一个对象的属性,它就可以被称为该对象的一个方法,当调用这个对象的方法时,this就绑定的就是这个对象

let obj = {
	name: 'world',
	fn: function(){
		console.log(this.name);
	}
}
obj.fn()

这时我就有一个大胆的猜想当函数为一个对象的属性时,this指向的是包含他且离它最近的一个对象

let obj = {
	name: 'world',
	b: {
		fn: function(){
			console.log(this.name);//undefined
		}
	}
}
obj.b.fn()
let obj = {
	name: 'world',
	b: {
		name: 'home',
		c:{
			fn: function(){
				console.log(this.name);//undefined
			}
		}
	}
}
obj.b.c.fn()

从这些结果,我们可以得出当函数为一个对象的属性时,this指向的是包含它且离它最近的一个对象
我们来加深一下对结论一的理解,我们稍微改一下上一个代码

let obj = {
	name: 'world',
	b: {
		name: 'home',
		c:{
			fn: function(){
				console.log(this.name);//window
			}
		}
	}
}
let t = obj.b.c.fn;
t();

3.构造函数调用模式

如果在调用函数时,前面用了new这个关键词来修饰,那么就创建了一个连接该函数prototype的对象,同时this就会绑定到该函数的对象上。

  • 没有返回值
    当new的方法没有返回值,this指向的是new的那个对象
function fn(){
	console.log(this);//fn()
}
let a = new fn();
  • 有返回值,但返回值不是对象
    当new的方法有返回值,但返回值不是对象,this依然指向的是new的那个对象(例外:如果返回值是null,this指向的是new的那个对象)
function fn(){
	this.name = 'Tom'
	return function(){
	};
}
let a = new fn();
console.log(a.name)//Tom
  • 有返回值,但返回值是引用数据类型(对象,数组。。。)

this指向的是return返回的那个对象

function fn(){
	this.name = 'Tom';
}
let a = new fn();
console.log(a.name)//Tom
function fn(){
	this.name = 'Tom';
	return [];
}
let a = new fn();
console.log(a.name)//undefine
function fn(){
	this.name = 'Tom';
	return {
		name: 'Zoo'
	};
}
let a = new fn();
console.log(a.name)//Zoo

4. call,apply,bind重指向模式

如果要详细讲解这三的用法,篇幅可能会有点长,我就简单的看一下他们的用法吧!
call(obj, param1, param2)
apply(obj, [param1, param2])
bind(obj, param1, param2)()
第一个参数必填
直接上代码

var name = 'Tom';
var o = {
	name: 'cat'
};
function sayName(){
	console.log(this.name);
}
sayName();//window
sayName.apply(o);//cat
sayName.call(o);//cat

很多源码使用apply就是用来传入数组参数(也可以说成去掉数组两边的中括号)。

三、练手题

我在网上找了三个练手题,看你是不是真的懂了

  • 第一个在这里插入图片描述
    第一个,使用的是:方法调用模式——没有返回值的,this指向的是person1,第二个使用的是:函数调用模式,this指向的是window
  • 第二个在这里插入图片描述
    javascript中的一个思想:万物皆对象,new B(),new C(),都是new了一个没有返回值的方法,this指向的是new出来的那个对象,this.n = 9999的意思是给new的这个B对象加了一个n:9999的属性,但是第二个var n = 8888,它只是函数内部的环境(不在作用域链上作用域链在四种会简单提一下),c.n是找不到n=8888的,只能找到该环境外层的原型中的4400。
  • 第三个在这里插入图片描述
    这个应该就比较简单了,第一个输出就是使用的函数调用模式,第二个就是方法调用模式——无返回值

四、(拓展方向)this存在是为了解决什么问题呢?

想明白this存在是为了解决什么问题,怎么也绕不开作用域链这个问题(不知道的可以去查查作用域链的资料),一个参数能识别该作用域向外到全局执行环境(window)遇到的第一个同名变量,所以与该参数同级的参数是无法在该作用域链找到的,为了解决这个问题就出了this这个关键字。
那我们看代码理解一下

let name = 'cat';
var obj = {
	name: 'Tom',
	fn: function(){
		console.log(name);//cat
	}
}
obj.fn();

可能我没说清楚,我只是给你提供了更加深入的方向

学习,最后都要回归书本,书本才是最好的老师,多看相关的书籍,你收获颇多

猜你喜欢

转载自blog.csdn.net/weixin_44206561/article/details/108349419
今日推荐