一篇文章带你了解javaScript中的this

157 阅读3分钟

this是javaScript中一个很特别的关键字,它被自动定义在所有函数的作用域中。
this存在的意义
先看一段代码

function identify(){
	return this.nameToUpperCase();
}

function speak(){
	var greeting = "Hello I'm " + identify.call(this);
	console.log(greeting);
}

var me = {
	name:"Zhou"
}
var you = {
	name:"Reader"
}
identify.call(me); //ZHOU
identify.call(you); //READER

speak.call(me);// Hello I'm ZHOU
speak.call(you);// Hello I'm READER

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

function identify(context){
	return context.name.nameToUpperCase();
}

function speak(context){
	var greeting = "Hello I'm " + identify.(context);
	console.log(greeting);
}

var me = {
	name:"Zhou"
}
var you = {
	name:"Reader"
}
identify(me); //ZHOU
speak(you); //// Hello I'm READER

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

this的指向的两种误解
1、指向自身
很容易就把this理解成函数自身,当使用函数递归或需要在事件处理函数中关闭事件处理器时会从函数内部引用自身。
通过下面的一个例子可以很容易就看出并非所想的那样指向函数自身

function foo(num){
	  console.log("foo"+num);
	  //记录foo被调用的次数
	  this.count ++;
	  
  }

  foo.count = 0;
  for(var i = 0;i < 10;i ++){
	if(i > 5){
	    foo(i);	
	}
  }
  console.log(foo.count); // 0

console.log()语句执行了4次,证明foo函数确实执行了4次,但是count的值却没有发生变化,这说明this并非指向函数自身。
2、指向它的作用域
第二种误解就是指向它所在的作用域,在某些情况下这是正确的,但是在其他情况下这是错误的。

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

this到底指向什么?
在理解this的绑定过程之前,首先要理解调用位置:调用位置就是函数在代码中的调用位置(而不是声明位置)。通常来说寻找调用位置就是寻找“函数被调用的位置”,但是做起来没那么简单,因为某些编程模式可能会隐藏真正的调用位置。
最重要的就是分析调用栈(就是为了达到当前执行位置所调用的所有函数)。我们关心的调用位置就在当前正在执行的函数的前一个调用中。
下面说明什么是调用栈和调用位置

function baz(){
	  //当前调用栈是baz,因此当前调用位置是全局作用域
	  console.log("baz");
	  bar();// bar的调用位置
  }
  function bar(){
	  //当前的调用栈是baz --> bar,因此当前调用位置在baz中
	  console.log("bar");
	  foo();//foo的调用位置
  }
  function foo(){
	//当前的调用栈是baz-->bar-->foo,因此当前调用位置在bar中
	console.log("foo");
  }
  baz();//baz的调用位置

this的4中绑定规则
1、默认绑定
首先要介绍的是最常用的函数调用类型:独立函数调用。这条规则可以看作是无法应用其他规则时的默认规则。

function foo(){
    console.log(this.a);
}