js的oop其实很简单,function本身就充当了类和构造函数的角色。然后通过传给构造函数的参数,完成类属性的赋值,从而实际化不同的对象。
可是,js的oop也有很让人头疼的地方,其中之一就是this的指向。在js中,普通的函数,this指向的是window对象,因为所有的全局函数都是window对象的方法。而对于类和对象中的方法,this指向的是这个类和对象。可是,this指针并不是那么老实的,如果在一个类中的方法,调用了另一个类的方法,那么这个this的指向就变得很奇怪了。举个简单的例子。
var a = 0;
function test()
{
this.a=123;
this.b = function()
{
alert(this.a);
}
this.init = function()
{
alert(this.a);
setTimeout(this.b,1000);
}
this.init();
}
var adang = new test();
你猜结果会是什么?一开始弹出一个123,然后一秒后又弹出一个123??错!一开始的确是弹出123,一秒后弹出的却是0!因为setTimeout是window对象的方法,所以做为参数被传入setTimeout方法的this.b()函数,运行的闭包空间,对象是window,而不再是test类,this指针指向了window,也就是说,里面的alert(this.a)等于window.a,而不是test.a。
这的确有点让人费解。想来想去,想到的一个解释是这样的:因为js中对复杂数据类型是通过传址方式进行赋值的,所以setTimeout中的第一个参数,也就是要运行的函数,是传递的this.b()这个方法的地址给setTimeout方法使用的,这个地址保存的是this.b方法中的所有"字符",是个string!!!然后再在setTimeout内部用eval(str)来运行。这么一来,this关键字完全没有连到test类的地址,而是直接使用新闭包的对象。
这个问题应该怎么解决呢??如果我想在setTimeout里正确运行test类的b方法,正解调用test的属性,应该怎么做呢?方法很简单,去掉this,把a由this.a换成var a,让它从一个公开属性,变成私有属性,因为a定义在test内部的最外一级,所以它的作用域是整个test类,类里的b方法可以调用到它。而它又去掉了this关键字,不会错误地指到别的对象上。
总结一下,心得就是,在用oop方式写js的时候,少用this关键字,除了必要的方法和属性写成公开属性/方法,应该尽量用var 定义成私有属性/方法。