学习javascript,必不可少的确定要理解this的指向。要学习this指向以前,就要先理解了我前面写的几篇文章,会更容易理解this的指向。javascript
前面的文章说到, 执行上下文的建立阶段,主要有三个内容:java
一、建立变量对象;二、初始化做用域链;三、肯定this的指向。git
前两个内容我都做了详细的解析了,在这里,是时候要说一下第三个内容了,肯定this的指向。其实this的指向从一些理论知识上理解,是很复杂的,看过很多文章都没有说的很清楚,反而说得人懵逼了。其实,this的指向是很是简单的,明确了它的规律,不要被太多代码表达形式的改变而影响了正常的认识思惟,那就能够了。github
好了,来个广泛例子:函数
//全局环境 var a = 10; function inner(){ var a = 20; console.log(this.a); } inner();
固然了,打印结果是10,this就是指向全局对象。学习
好了,该解析this了,咱们都知道this的指向是函数被调用的时候肯定的。this
简单直接说结论:经过对象访问属性的方式执行函数,this就是指向这个对象,其余状况,严格模式下都是指向undefined,非严格模式下都是指向全局对象。code
先解析上面例子,上面的inner函数是在全局环境中直接调用的:inner( ),你们能够理解这个调用,就是这一对方括号(),因此它是指向全局对象,因此this.a就是10。对象
//全局环境 var a = 10; var example = { a : 20, b : this.a + 10 } console.log(example.b);
打印结果是多少?30吗?错了,不是经过example这个对象访问b属性,因此b里面的this就是指向example吗?错了。ip
我说的是对象访问属性的方式执行函数,你这个b属性内容不是函数。因为example是在全局环境中声明的,因此里面的this就是指向全局对象,或者说,this的肯定是函数被执行时候肯定的,你的函数呢?往上找,就是全局对象这个大函数了,因此这个this就是指向全局对象。
固然了,若是你将example放进去某个函数里面,对照一下个人结论,就会知道这个this在严格模式下就会指向undefined,非严格模式就是指向全局对象。例子以下:
//非严格模式下的全局环境 var a = 10; function outer(){ var example = { a : 20, b : this.a + 10 } return example.b; } outer();//打印结果为20
//严格模式下的全局环境 'use strict' var a = 10; function outer(){ var example = { a : 20, b : this.a + 10 } return example.b; } outer();//执行会报错,由于this指向undefined
还问为何?由于outer函数被执行时候这个this才肯定啊,而outer这个函数是单独调用啊,直接outer( )这样调用啊,因此就是结论中那样啊。
好了,那怎样是属于对象访问属性的方式执行函数呢?再来例子:
//全局环境 var a = 10; var example = { a : 20, b : function(){ return this.a; } } console.log(example.b());
好了,此次打印结果是20了,由于经过了example访问b属性方式执行函数的,经过这个一点运算符的属性访问方式,叫作成员访问。稍微改改再来例子:
//全局环境 var a = 10; var example = { a : 20, b : function(){ return this.a; } } var c = example.b; console.log(c());
仍是20吗?不是了,非严格模式是10,严格模式报错(后面都是非严格模式的例子),由于调用函数c,前面只是经过example.b将函数的地址传给了c而已,你调用函数时候,仍是单独调用啊。开始懂了对不对,再来例子:
//全局环境 var a = 10; function runAway(){ return this.a; } var example = { a : 20, b : runAway } console.log(example.b());
若是你不假思索就能说是20的话,证实你已迈出了一大步了,同一个道理,是经过对象访问属性的方式执行函数的,我管你的b属性是直接指向函数,仍是经过函数声明指向函数的,反正你的this就是指向对象example。
好了,结合上面的再改一改例子:
//全局环境 var a = 10; function runAway(){ return this.a; } function worker(fn){ fn(); } var example = { a : 20, b : runAway } worker(example.b);
可能你会说,经过example.b这样的的方式,我无论你有没有跳出来的runAway,this确定是指向example啦,那就要重温一下个人结论了,我说的是经过对象访问属性的方式执行函数,你执行了吗,你有一对方括号吗?可能你会说,他们传入去worker函数,里面就会加一对方括号执行啊,那就错了。
经过这种方式的执行函数,其实已经变味了,这种状况和上面的例子:var c = example.b,而后c( )执行函数式同样的,你只不过经过example.b将这个函数地址传入了worker函数,而后执行而已。
因此上面这个例子,就是结论中的其余状况咯,严格模式this指向undefined(固然这个例子会报错,由于undefined没有a属性),非严格模式指向全局对象(固然这个例子会打印undefined,由于全局对象没有b属性)。
好了,最后再举一下其余例子:
//全局环境 var a = 10; var example = { a : 20, b : function(){ return this.a; } } //例子一 console.log(example.b()); //打印结果为20 //例子二 console.log((example.b)()); //打印结果为20 //例子三 console.log((false || example.b)()); //打印结果为10
好了,在例子一中,很清楚明白就是常规的this指向了example。
例子二中,你加了一个括号也没用啊,我没有将它的函数地址赋值其余什么变量啊,因此和例子一也是同样的。
至于例子三,咱们能够这样理解,你在括号里面进行了一些其余运算,因此经过example.b这个方式只是拿了函数地址出来运算,因此在例子三中,括号的结果是example.b这个结果,因此是拿到了一个函数的地址,最后调用的时候仍是单独调用啊,就相似前面例子的worker函数那样啊。
网上还有不少像例子三那样的古灵精怪的例子,其实很简单,你运算过了,最后出来的东西再加方括号调用,就是单独调用了。
最后,好像忘了个很经常使用的构造函数的this指向:
//先来个构造函数Mankind function Mankind(name){ this.name = name; } //实例化对象Dad var Dad = new Mankind('BaBa'); console.log(Dad.name); //打印结果为BaBa
很明白了,经过构造函数实例化对象,构造函数里面的this就是指向这个实例化对象了。