深度解析javascript中的this(一)

文章目录

  • 前言
  • 正文
    • 为什么需要使用this
    • 对this的错误认知
      • 指向函数自身
      • 指向函数的作用域
    • this指向函数调用者
  • 小结

前言

      this 关键字是 JavaScript 中最复杂的机制之一。它是一个很特别的关键字,被自动定义在所有函数的作用域中。我记得自己从开始学习javascript开始就开始不停地被人问到关于this的知识,自己也从来不敢保证自己回答的是对的。毫无疑问,在缺乏清晰认识的情况下,this 对开发者来说完全就是一种魔法,这系列文章将就this做一个深度解析,帮助大家打破看似不可打破的魔法

正文

为什么需要使用this

      我们还是一如既往从一个例子开始看这个问题:

function identify() {
	return this.name.toUpperCase();
}
function speak() {
	var greeting = "Hello, I'm " + identify.call( this );
	console.log( greeting );
}
var me = {
	name: "Kyle"
};
var you = {
	name: "Reader"
};
identify.call( me ); // KYLE
identify.call( you ); // READER
speak.call( me ); // Hello, 我是 KYLE
speak.call( you ); // Hello, 我是 READER

      这段代码可以在不同的上下文对象(me 和 you)中重复使用函数 identify() 和 speak(),不用针对每个对象编写不同版本的函数。如果不使用 this,那就需要给 identify()和 speak() 显式传入一个上下文对象。

function identify(context) {
	return context.name.toUpperCase();
}
function speak(context) {
	var greeting = "Hello, I'm " + identify( context );
	console.log( greeting );
}
identify( you ); // READER
speak( me ); //hello, 我是 KYLE

      this 提供了一种更优雅的方式来隐式“传递”一个对象引用,因此可以将 API 设计得更加简洁并且易于复用。随着你的使用模式越来越复杂,显式传递上下文对象会让代码变得越来越混乱,使用 this则不会这样。

对this的错误认知

      太拘泥于“this”的字面意思就会产生一些误解。有两种常见的对于 this 的解释,但是它们都是错误的。

指向函数自身

      人们很容易把 this 理解成指向函数自身,这个推断从英语的语法角度来说是说得通的。包括我,在初学javascript的时候常将this指向为当前的函数。针对这个问题我们举一些例子给大家说明:

function foo(num) {
	console.log( "foo: " + num );
	// 记录 foo 被调用的次数
	this.count++;
}
foo.count = 0;
var i;
for (i=0; i<10; i++) {
	if (i > 5) {
		foo( i );
	}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo 被调用了多少次?
console.log( foo.count ); // 0

      这个例子很直接地打破了我们之前的观点,foo.count的值是0,这表明this并不是指向foo函数本身,那么这里实际修改的count的是哪里的呢?可能有些同学猜到了,window.count这时候值为4。this的指向在不考虑箭头函数的情况下,会指向这个函数的调用者,而不是这个函数的本身, foo(i)的调用可以理解成window.foo(i),所以this也会指向到window。如果这里就是想要修改foo.count怎么办呢,就需要调整一下foo的调用

function foo(num) {
	console.log( "foo: " + num );
	// 记录 foo 被调用的次数
	// 注意,在当前的调用方式下(参见下方代码),this 确实指向 foo
	this.count++;
}
foo.count = 0;
var i;
for (i=0; i<10; i++) {
	if (i > 5) {
	// 使用 call(..) 可以确保 this 指向函数对象 foo 本身
	foo.call( foo, i );
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo 被调用了多少次?
console.log( foo.count ); // 4

指向函数的作用域

      需要明确的是,this 在任何情况下都不指向函数的词法作用域。在JavaScript 内部,作用域确实和对象类似,可见的标识符都是它的属性。但是作用域“对象”无法通过 JavaScript代码访问,它存在于 JavaScript 引擎内部。这里出示一段一个公共社区中互助论坛的精华代码来给大家解释一下这个问题

function foo() {
	var a = 2;
	this.bar();
}
function bar() {
	console.log( this.a );
}
foo(); // ReferenceError: a is not defined

      我们始终要牢记在不考虑箭头函数的情况下,this将指向函数的调用者,而全局作用域下的变量都被绑定在window上,所以this也会指向window。这里不难理解foo中的this会指向window,而bar呢,this也会指向window,别忘了之前我们说的javascript的作用域规则,javascript是词法作用域,函数的作用域只与它定义的位置有关,而不会因为bar在foo中被调用就有什么不同,全局环境下是没有a变量的,所以会有上述的问题

this指向函数调用者

      我们始终要牢记在不考虑箭头函数的情况下,this将指向函数的调用者,而全局作用域下的变量都被绑定在window上,所以this也会指向window。这里不对箭头函数的情况做一个额外说明,感兴趣的同学可以查阅别的文章,网上类似的文章资料也很多,但是这里可以稍稍提一下,箭头函数的this的指向是指向箭头函数的上下文作用域,这样的原因是因为箭头函数本身并没有调用者的说法

小结

      对于那些没有投入时间学习 this 机制的 JavaScript 开发者来说,this 的绑定一直是一件非常令人困惑的事。包括我自己,在认真研究this之前,对this可能更多地是一些很模糊的概念,始终牢记,在不考虑箭头函数的情况下,this指向函数的调用者,也不要因为调用的位置而影响自己的判断,javascript作用域规则采用词法作用域,无论在哪里调用,永远以定义的位置为基准
       小伙伴们今天的学习就到这里了,如果觉得本文对你有帮助的话,欢迎转发,评论,收藏,点赞!!!
       每天学习进步一点点,就是领先的开始。如果想继续提高,欢迎关注我,或者关注公众号”祯民讲前端“。大量前端技术文章,面试资料,技巧等助你更进一步!

你可能感兴趣的:(你不知道的javaScript,javascript,前端,this)