细数那些年我们使用过的this
This介绍
关于Javascript中的this,相信接触过的人都不会感到陌生。可以说javascript之所以如此的’强大’,this
可以说是功不可没。它有以下几个特点:
- 随着javascript函数的不同调用方式,
this
的取值可能会不同(this在global下指向的是window
) - 在函数的标识符解析的过程中,
this
的解析仅仅只限于当前函数作用域,而不会通过作用域链向上查找。 this
与Function.prototype.call/apply
和Function.prototype.bind
的相结合,使得有趣的事情发生。(this
的指向变成我们所指定的)
关于this的常见用法相信你已经看了不少了,我google了一些还算不错的:
接下来的内容希望你能先看完上面的资料,至少有一个大概的印象,这样才能愉快的查看下面的栗子~~
举个栗子
1 | window.name = 'global'; |
不要问我为什么是jQuery
,最近刚好在看jQuery源码,就酱==
接下来根据你的判断分别写下1,2,3,4,5处console出的值。
+
+
+
+
+
+
防作弊线---------------
+
+
+
+
+
+
+
让我们看下结果(为了方便查看我吧代码全部截取下来并加上一些注解):
1 | window.name = 'global'; |
是不是和你分析的一样呢?我们一个个来分析下吧。
console 1
1 | console.dir(objA.getName()); // 'new obj' |
这里的objA
是jQuery的一个实例,getName
是jQuery原型上的方法,所以此处的getName
方法是在实例上面通过__pro__
属性查找并调用在jQuery.prototype
上的getName
方法。
所以我们可以知道通过原型链的查找并调用执行的function
中的this
指向的就是这个调用方法的实例。this === objA
console 2
1 | console.dir(getName()); // 'global' |
这里的getName
是我们通过chrome和firefox私有属性__proto__
(它指向的是实例的构造器的原型)获取到的jQuery.prototype
上的方法。但是在这里getName
中保存的是指向jQuery.prototype.getName
的指针,他是在全局环境下运行的所以这里毫无疑问this === window
也就是说this.name === window.name
console 3
1 | console.dir(objA.__proto__ .getName()); // 'jQuery.prototype' |
这里很明显也是通过访问实例的私有属性__proto__
进而执行jQuery.prototype.getName
,因为这里的执行环境是相当于调用jQuery.prototype
对象上面的方法,故而this === jQuery.prototype
console 4
1 | console.dir(objB.somemethod()); // 'simmer' |
我们知道getName
变量保存着指向jQuery.prototype.getName
方法的引用,又由于在javascript中对象的赋值时按照引用来赋值的,所以这里呢objB.somemethod = getName;
中objB的somemethod
方法也保存指向jQuery.prototype.getName
方法的引用,所以当通过objB.somemethod()
这种形式调用jQuery.prototype.getName
方法时,这个方法是作为对象的方法调用的,故而有this === objB
console 5
1 | console.dir(objC); // chrome返回'jQuery.getName' Firefox返回'[object Object]' |
最后一种情况也比较简单,我们知道函数的调用分为2种情况,一种是作为普通函数进行调用,另外一种就是通过使用new
操作符的形式进行调用。熟悉javascript的童鞋应该知道javascript的类正是通过这种new的形式创建的。简单来说就是通过new
来调用函数,在函数内部会自动新建一个对象,而在这个函数内部使用的this
则会自动指向这个新建的对像,最后在自动返回这个新建对象(在没有return的情况下)。类似于:1
2var obj = {}; // 新建对象
constructor.apply(obj); // 更正this 指向新的对象
但是这里提前返回了this.name
,他是一个字符串,并不是对象,我通过typeof objC
得到object
,所以javascript解析器会默认返回一个空的对象。,在chrome中返回的jQuery.getName
可能是默认返回构造器的引用组成的名字,相比指向firefox就靠谱多了,直接返回'[object Object]'
表示这是一个对象
小总结
- JavaScript中的
this
可以有不同的取值,这是根据某个函数的具体调用情况来看的。 - 我们知道当javascript在某个函数内部没有查找到需要的变量时候,会沿着作用域链向外层作用域环境中(全局环境是window)中查找变量。而神奇的
this
则不再这个变量查找机制范围内,每个函数内的this
取值是要到函数运行时候才能确定的,这也是为什么javascript有着如此迷人的魅力原因所在。 - 要想知道
this
的取值,关注函数具体的调用方式,全局调用?对象方法调用?使用new
操作符构造实例调用?实例公有方法调用(__proto__
)?还是通过Function.prototype.call/apply
自定义this
调用?亦或者是通过Function.prototype.bind
(ES5)调用?(注意:每个函数只能bind一次,且以第一次bind为准)
(完)
由于水平有限,如有错误,欢迎在下方进行评论指出。