JavaScript的this关键字
和一些面向对象的语言一样,JavaScript也支持this关键字,顾名思义,this关键字指代本对象,在传统的面向对象语言中,this代表该方法所属的对象,或者该对象的指针。
在JavaScript中没有类的概念,this方法的指代含义也有些许的变化,指代的是调用该方法的对象。
还是以上次的程序作为例子:
var User = function() { this.username = 'username'; this.password = 'password'; } User.prototype.toString = function() { return this.username + ':' + this.password; };
toString方法中就使用了this关键字来指代调用者本身,一般情况下,调用者和该方法的所属对象是一致的,这种情况下,就与其他语言没什么不同。不过,JavaScript中调用者和方法所属的对象并不一定是一致的,许多情况下与闭包特性结合,也能产生许多特殊的效果。下面是一个稍微复杂的例子。
var x = function() { this.show = function(msg, func, scope) { document.write(msg + " : " + this.value + '<br />'); if (scope === undefined) scope = this; func.apply(scope, []); func.call(scope); } }; var y = new x(); x.prototype.value = 4; y.value = 5; var z = new x(); z.value = 6; var w = new x(); x.prototype.value = 7; y.show('value is', function() { document.write('value in scope : ' + this.value + '<br />'); }, z); y.show('value is', function() { document.write('value in scope : ' + this.value + '<br />'); }, x.prototype); y.show('value is', function() { document.write('value in scope : ' + this.value + '<br />'); }, w);
x构造函数定义了一个show方法,首先输出调用者的value值,然后如果scope没有传入,则定义为方法的调用者本身。
随后出现了两个方法,分别为apply和call,这两个方法是所有function都具有的,作用是强制指定某对象作为该方法的调用者,两者除了调用格式略有不同,作用是相同的。这两句话以scope的身份调用了func。
后面定义了y、z、w三个变量,都分别是x的实例,接着以y的身份调用了3次show方法,只有scope参数传入了不同的值。
第一次传入了对象z,此时y作为show的调用者,而show中的参数匿名函数func的调用者却被设定为z,因此输出结果为:
value is : 5 value in scope : 6 value in scope : 6
第二次传入x.prototype,原理如上面相同,show的func参数是由x.prototype调用的,因此输入结果为:
value is : 5 value in scope : 7 value in scope : 7
第三次传入了对象w,原理也和上面相同,func的调用者是w,那么此时w的值是多少呢?我们在实例化w以后,我们修改了x.prototype.value的值,那么此时w的value应该是x.prototype.value修改前的值还是修改后的值呢?
答案是修改后的值,结果是:
value is : 5 value in scope : 7 value in scope : 7
因为w并没有显式定义value属性,因此w的value属性是位于其__proto__属性中,也就是x.prototype的引用,因此当x.prototype发生了改变,对于w也是会同时产生影响,具体关于prototype的原理和行为,请参考之前的其他文章。