javascript 函数作用域中的关键字this的指向

对于初学者来说,关键字this总是让人捉摸不透,甚是复杂,但是其实,只要你摸透了其中关键所在,便也无甚烦恼了;

其实this在函数中指向的是什么,都是围绕两个原则,就是谁引用他他就指向谁与就近原则;

一般this的指向性问题分为下面几类,我们来看具体实例

一、普通函数中的this关键字
//示例一
function f1(){
	this.a = 5;
}
f1();
console.log(window.a) // 5;

//示例二
var b = 10;
function f2(){
	this.b = 20;
}
f2();
console.log(window.b) //20;
复制代码

上面两个例子都是普通函数,他们指向的都是window,所以我们的结论是: 普通函数中this的指向都是window

可能你会问,上面不是说,this指向的都是调用他的那个对象吗?那函数自执行,this的指向不应该是函数本身吗?

其实啊,函数自己调用自己的时候,就相当于是window在调用他,像示例一种,f1()相当于是window.f1();

既然是window调用他,那么this的指向就是window了

二、对象中的this关键字

同样我们先看下面例子:

//示例一
var obj1 = {
	a : 5,
	f1 : function(){
		console.log(this.a) // 5
		console.log(this === obj1) //true
	}
}
obj1.f1(); 

复制代码

从给出的例子我们可以看出来,当函数作为对象的属性来调用时,this的指向便指向了对象自身,这就是说既然你函数都是我对象的一个属性了,那么你里面的this当然指向我,这种指向是一种隐式绑定this的现象,但是如果我们解除了这种隐式绑定呢?

接下来我们将例子变一下:

//变异示例一
var obj2 = {
	a : 5,
	f2 : function(){
		console.log(this.a); //undefined
		console.log(this === obj2) //false
	}
}
var init = obj2.f2 //重点看这里
init();
复制代码

还是那句话,谁调用指向谁,从变异示例一可以看出,obj.f2这里并没有调用函数f2,他只是将函数赋值给了变量init而已,所以这里调用函数f2的不再是对象obj2了,因为已经将f2的隐式绑定给解除了

所以必然this指向的不在是obj2,那么obj2中的属性自然是调用不到了,this也不可能等于obj2了,那么这里的this究竟指向了谁呢?

一起看init()这里,在这里调用了函数,变量的是全局变量,他的顶级对象在这里是window,所以init() === window.init()是一样的,所以最后this指向的是window;

这里我们要注意,一定要看清楚函数是在哪里调用的,这样我们才能去判断this指向的是什么

再将上面的示例变一下:

var obj3 = {
	a : 5,
	obj4 : {
		a : 10,
		f3 : function(){
			console.log(this.a) //10
		}
	}
}
obj3.obj4.f3();
复制代码

这里输出的为什么是10呢?按最终调用的应该是对象obj3,那么他下面的a不应该是5吗?

还记得我们上面说过一个词叫就近原则吗?虽然最终调用的是obj3,但是在遵循就近原则的情况下,调用他的是obj4,所以this指向的是obj4,那么必然打印出来的就是10了

最后我们附加一个示例,这也是之前有个人有些疑问的地方,我觉得值得说一下

var obj5 = {
	a : 5,
	f5 : function(){
		console.log(this.a) // 5
		console.log(this === obj5) //true
	}
}

var init = obj5;
init.f5();
复制代码

在这里直接将对象obj5赋值给变量init,然后由变量去调用f5,实则和obj5去调用f5是一样的,this指向的还是对象obj5,所以在这里一定要注意,千万不要认为是window调用函数f5

三、call中的this关键字

call() 、bind()、apply()这类方法绑定this关键字又称为显示绑定,明面上我们完全可以看到他指向了谁

function f7(){
	this.x = function(){
		console.log(this.a) // 20
	}
}
var obj5 = {
	a : 20
}
f7.call(obj5);
obj5.x();
复制代码

通过call()方法,函数f7被封装为对象obj5的一个属性,this的值指向了调用函数的对象obj5了,

通过对call()方法的使用,我们知道,如果第一个参数为null,或者不写,那么其间的对象就是window,我们看下面示例

function f8(){
	this.x = function(){
		console.log(this.a) // 15
	}
}
var obj6 = {
	a : 20
}
var a = 15;
f8.call(null);
x();
//我们可以看到,这段函数里面并没有定义过函数x,但是在这里可以直接调用
//这说明,我们的this指向了window,x() === window.x();
复制代码
四、构造函数中的this关键字

先看示例:

function F1(){
	this.a = 10;
	this.b = 20;
	this.f6 = function(){
		this.c = this.a+this.b;
		console.log(this.c); //30
		console.log(this === F1) //false
	}
}

var oInit = new F1();
oInit.f6();
复制代码

这里就很奇怪了,明明所有症状都表现为this指向的就是构造函数F1,但是为什么this没有指向F1呢,在这里,我们需要了解,在new F1()的这个过程中,new到底做了什么?

看下面代码:

//new 过程如下
{}
//new 先创建了一个空对象{}(第一步)
{}.__proto__ = F1.prototype 
//空对象的隐式原型指向F1的原型对象(第二步)
F1.call({});
//利用call方法继承了F1中所有属性与方法,这一步将F1内部的this指向指向了这个空对象
// 继而会执行这个空对象继承而来的内容,在最后
return this; 
//在我们不主动改变return 内容的时候,默认会将this返回出去	(第四步)
//而Oinit = {}
// 自然而然的最后this就指向了Oinit
复制代码

我看到很多人说,构造函数中的this指向的是构造函数本身,这种说法是不正确的, 他就算瞎指也不会指向函数本身,谁去调用他是吧,他指向的new的实例,所以一定要注意这里

在构造函数中使用return有个特殊情况,我们来看看

//示例一
function f9(){
	this.a = 10;
	var obj10 = {};
	obj10.a = 20;
	return this.a
}
var init2 = new f9();
init2.a;


//示例二
function f9(){
	this.a = 10;
	var obj10 = {};
	obj10.a = 20;
	return obj10;
}
var init2 = new f9();
init2.a;

复制代码

这两个示例有点特殊,特殊在于return出来的值,这里先不说this指向的问题,说说return返回的值的问题,在函数中如果返回的是一个对象(包括函数,数组,对象),即返回出来的是对象本身,就会覆盖原来的this对象,如果返回的是值类型, 则是返回this对象;

所以从表面上看是觉得构造函数的实例化对象在调用参数,其实不然,内部正真调用的是返回的对象,那么自然this值指向了返回的对象

五、事件中的this关键字

1、事件中直接使用this

<div class="clickMe">click me</div>
<script>
	var clickDom = document.querySelector('.clickMe');

	clickDom.onclick = function(){
		console.log(this.className) //clickMe
	}
</script>
复制代码

这里this指向了操作事件的元素,所以如果直接在事件中使用this,那么this则指向操作事件的元素;

2、事件中的函数使用this;

<div class="clickMe">click me</div>
<script>
	var clickDom = document.querySelector('.clickMe');

	clickDom.onclick = function(){
		function test(){
			console.log(this.className) //undefined
			console.log(this) //[object Window]
		}
		test();
	}
</script>
复制代码

这里指向了window,我们是不是可以得出结论,如果在事件中的函数去调用this,那么就看该函数是谁调用的呢?先不急,我们再看下面一个示例:

<div class="clickMe">click me</div>
<script>
	var clickDom = document.querySelector('.clickMe');

	clickDom.onclick = function(){
		var obj7 = {
			a : 10,
			f7 : function(){
				console.log(this.a); //10
			} 
		}
		obj7.f7();
	}
</script>
复制代码

这里我们完全可以确定,就算事件中,this的指向还是遵循一个原则,谁调用指向谁 + 就近原则;

事件后面跟的是一个匿名函数,而调用这个匿名函数的则是事件中的元素,所以自然是指向了调用事件的元素了,实则上面的示例无不在佐证这一原则

好了,关于this的指向性问题,就讲到这里了,还是那句话,谁调用指向谁 + 就近原则 ,万般皆虚幻,透过现象看本质,才能正真知道this指向的是谁


原创不易,总结不易,手打不易,转载时请注明出处,谢谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值