JAVA中关于this和that的一些知识
新手在入门 Java 的过程中,一定会踩很多关于 this 的坑,出现问题的本质就是 this 指针的指向和自己想的不一样。笔者在入门学习的过程中,也踩了很多坑,于是便写下本篇文章记录自己“踩坑”历程。
一。 this 在哪里?
在上篇《从 Java 作用域说开去》分析中,我们知道,在 Execution Context 中有一个属性是 this,这里的 this 就是我们所说的 this 。this 与上下文中可执行代码的类型有直接关系,this 的值在进入执行上下文时确定,并且在执行上下文运行期间永久不变。
this 到底取何值?this 的取值是动态的,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了。因为 this 的取值是执行上下文环境的一部分,每次调用函数,都会产生一个新的执行上下文环境。
所以 this 的作用就是用来指明执行上下文是在哪个上下文中被触发的对象。令人迷惑的地方就在这里,同一个函数,当在不同的上下文进行调用的时候,this 的值就可能会不同。也就是说,this 的值就是函数调用表达式(也就是函数被调用的方式)的 caller。
二。 this & that 具体指的是谁?
目前接触的有以下14种情况,笔者打算一一列举出来,以后如果遇到了更多的情况,还会继续增加。
既然 this 是执行上下文确定的,那么从执行上下文的种类进行分类,可以分为3种:
那么接下来我们就从 Global Execution Context 全局执行上下文,Function Execution Context 函数执行上下文,Eval Execution Context Eval执行上下文 这三类,具体谈谈 this 究竟指的是谁。
(一)。 全局执行上下文1. 非严格模式下的函数调用
这是函数的最通常用法,属于全局性调用,因此 this 就代表全局对象 Global。
var name = ‘halfrost’;function test() { console.log(this); // window console.log(this.name); // halfrost}test();
在全局上下文(Global Context)中,this 总是 global object,在浏览器中就是 window 对象。
2. 严格模式下的函数调用
严格模式由 ECMA 5.1引进,用来限制 Java 的一些异常处理,提供更好的安全性和更强壮的错误检查机制。使用严格模式,只需要将 ‘use strict’ 置于函数体的顶部。这样就可以将上下文环境中的 this 转为 undefined。这样执行上下文环境不再是全局对象,与非严格模式刚好相反。
在严格模式下,情况并不是仅仅是 undefined 这么简单,有可能严格模式夹杂着非严格模式。
先看严格模式的情况:
‘use strict’;function test() { console.log(this); //undefined};test();
上面的这个情况比较好理解,还有一种情况也是严格模式下的:
function execute() { ‘use strict’; // 开启严格模式 function test() { // 内部函数也是严格模式 console.log(this); // undefined } // 在严格模式下调用 test() // this 在 test() 下是 undefined test(); // undefined } execute();
如果严格模式在外层,那么在执行作用域内部声明的函数,它会继承严格模式。
接下来就看看严格模式和非严格模式混合的情况。
function nonStrict() { // 非严格模式 console.log(this); // window } function strict() { ‘use strict’; // 严格模式 console.log(this); // undefined }
这种情况就比较简单了,各个模式下分别判断就可以了。
(二)。函数执行上下文3. 函数调用
当通过正常的方式调用一个函数的时候,this 的值就会被设置为 global object(浏览器中的 window 对象)。
严格模式和非严格模式的情况和上述全局执行上下文的情况一致,严格模式对应的 undefined ,非严格模式对应的 window 这里就不再赘述了。
4. 方法作为对象的属性被调用
var person = { name: “halfrost”, func: function () { console.log(this + “:” + this.name); }};person.func(); // halfrost
在这个例子里面的 this 调用的是函数的调用者 person,所以会输出 person.name 。
当然如果函数的调用者是一个全局对象的话,那么这里的 this 指向又会发生变化。
var name = “YDZ”;var person = { name: “halfrost”, func: function () { console.log(this + “:” + this.name); }};temp = person.func;temp(); // YDZ
在上面这个例子里面,由于函数被赋值到了另一个变量中,并没有作为 person 的一个属性被调用,那么 this 的值就是 window。
上述现象其实可以描述为,“从一个类中提取方式时丢失了 this 对象”。针对这个现象可以再举一个例子:
var counter = { count: 0, inc: function() { this.count ++; }}var func = counter.inc;func();counter.count; // 输出0,会发现func函数根本不起作用
这里我们虽然把 counter.inc 函数提取出来了,但是函数里面的 this 变成了全局对象了,所以 func() 函数执行的结果是 window.count++。然而 window.count 根本不存在,且值是 undefined,对 undefined 操作,得到的结果只能是 NaN。
非常好我支持^.^
(5) 83.3%
不好我反对
(1) 16.7%