JavaScript 类
一、javascript也作为一种面向对象的语言,它也可以有类,有对象,可以用new来创建类实例,用实例调用它的方法。只是javascript中类形式与java以及其他面向对象语言有所差异而已。
二、类举例
function className()
{
?this.a = 8;
?this.setA = function (parame)
?{
??this.a = parame;
?};
}
function testClass()
{
?var cls = new className();
?document.write(cls.a);
?cls.setA(9);
?document.write(cls.a);
}
================================
深入理解javascript类,参考一下
================================
三、this关键字
this属性表示当前对象,如果在全局作用范围内使用this,则指代当前页面对象window; 如果在函数中使用this,则this指代什么是根据运行时此函数在什么对象上被调用。 我们还可以使用apply和call两个全局方法来改变函数中this的具体指向。 先看一个在全局作用范围内使用this的例子:
<?script?type="text/javascript">? ????console.log(this?===?window);??//?true ? ????console.log(window.alert?===?this.alert);??//?true ? ????console.log(this.parseInt("021",?10));??//?10 ? <?/script> ?
函数中的this属性是在运行时决定的,而不是函数定义时,如下: //?定义一个全局函数 ? function?foo()?{ ? ????console.log(this.fruit); ? } ? //?定义一个全局变量,等价于window.fruit?=?"apple"; ? var?fruit?=?"apple"; ? //?此时函数foo中this指向window对象 ? //?这种调用方式和window.foo();是完全等价的 ? foo();??//?"apple" ? ? //?自定义一个对象,并将此对象的属性foo指向全局函数foo ? var?pack?=?{ ? ????fruit:?"orange", ? ????foo:?foo ? }; //?此时函数foo中this指向window.pack对象 ? pack.foo();?//?"orange"?? 全局函数apply和call可以用来改变函数中this属性的指向,如下: //?定义一个全局函数 ? ?function?foo()?{ ? ?????console.log(this.fruit); ? ?} ? ? ? ?//?定义一个全局变量 ? ?var?fruit?=?"apple";?? ?//?自定义一个对象 ? ?var?pack?=?{ ? ?????fruit:?"orange"? ?}; ? ? ? ?//?等价于window.foo(); ? ?foo.apply(window);??//?"apple" ? ?//?此时foo中的this?===?pack ? ?foo.apply(pack);????//?"orange" ? 注:apply和call两个函数的作用相同,唯一的区别是两个函数的参数定义不同。 ? 因为在JavaScript中函数也是对象,所以我们可以看到如下有趣的例子: ? //?定义一个全局函数 ? function?foo()?{ ? ????if?(this?===?window)?{ ? ????????console.log("this?is?window."); ? ????} ? } ? ? //?函数foo也是对象,所以可以定义foo的属性boo为一函数 foo.boo?=?function()?{ ? ????if?(this?===?foo)?{ ? ????????console.log("this?is?foo."); ? ????}?else?if?(this?===?window)?{ ? ????????console.log("this?is?window."); ? ????} ? }; ? //?等价于window.foo(); ? foo();??//?this?is?window. ? ? //?可以看到函数中this的指向调用函数的对象 ? foo.boo();??//?this?is?foo. ? ? //?使用apply改变函数中this的指向 ? foo.boo.apply(window);??//?this?is?window. ?
?
四、prototype属性本质上还是一个JavaScript对象。并且每个函数都有一个默认的prototype属性。如果这个函数被用在创建自定义对象的场景中,我们称这个函数为构造函数。比如下面一个简单的场景:
prototype用在创建自定义对象中 //?构造函数 ? function?Person(name)?{ ? ????this.name?=?name; ? }?? ? //?定义Person的原型,原型中的属性可以被自定义对象引用 Person.prototype?=?{ ? ????getName:?function()?{ ? ????????return?this.name; ? ????} ? } ? var?zhang?=?new?Person("ZhangSan"); ? console.log(zhang.getName());???//?"ZhangSan"? 作为类比,我们考虑下JavaScript中的数据类型 - 字符串(String)、数字(Number)、数组(Array)、对象(Object)、日期(Date)等。 我们有理由相信,在JavaScript内部这些类型都是作为构造函数来实现的,比如: ?
//?定义数组的构造函数,作为JavaScript的一种预定义类型 function?Array()?{ ? ????//?... ? } ? ? //?初始化数组的实例 ? var?arr1?=?new?Array(1,?56,?34,?12); ? //?但是,我们更倾向于如下的语法定义: ? var?arr2?=?[1,?56,?34,?12];? ? ? ? 同时对数组操作的很多方法(比如concat、join、push)应该也是在prototype属性中定义的。 实际上,JavaScript所有的固有数据类型都具有只读的prototype属性(这是可以理解的:因为如果修改了这些类型的prototype属性,则哪些预定义的方法就消失了), 但是我们可以向其中添加自己的扩展方法。 ? //?向JavaScript固有类型Array扩展一个获取最小值的方法 ? Array.prototype.min?=?function()?{ ? ????var?min?=?this[0]; ? ????for?(var?i?=?1;?i?<??this.length;?i++)?{ ? ????????if?(this[i]?<??min)?{ ? ????????????min?=?this[i]; ? ????????} ? ????} ? ????return?min; ? }; ? ? //?在任意Array的实例上调用min方法 ? console.log([1,?56,?34,?12].min());??//?1? ? 注意:这里有一个陷阱,向Array的原型中添加扩展方法后,当使用for-in循环数组时,这个扩展方法也会被循环出来。 下面的代码说明这一点(假设已经向Array的原型中扩展了min方法): var?arr?=?[1,?56,?34,?12]; ? var?total?=?0; ? for?(var?i?in?arr)?{ ? ????total?+=?parseInt(arr[i],?10); ? } ? console.log(total);???//?NaN? 解决方法也很简单: var?arr?=?[1,?56,?34,?12]; ? var?total?=?0; ? for?(var?i?in?arr)?{ ? ????if?(arr.hasOwnProperty(i))?{ ? ????????total?+=?parseInt(arr[i],?10); ? ????} ? } ? console.log(total);???//?103? ? 五、parseInt的使用 ①parseInt(string,radix) 函数可解析一个字符串,并返回一个整数。其中radix非必须,表示要解析的数字的基数。该值介于 2 ~ 36 之间。如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。当参数 radix 的值为 0,或没有设置该参数时,parseInt() 会根据 string 来判断数字的基数。举例,如果 string 以 "0x" 开头,parseInt() 会把 string 的其余部分解析为十六进制的整数。如果 string 以 0 开头,那么 ECMAScript v3 允许 parseInt() 的一个实现把其后的字符解析为八进制或十六进制的数字。如果 string 以 1 ~ 9 的数字开头,parseInt() 将把它解析为十进制的整数。 ②实例说明 parseInt("11"); //返回 11 parseInt("010"); //未定:返回 16 或 8 六、类继承
说到Javascript的类继承,就必然离不开原型链,但只通过原型链实现的继承有着不少缺陷。 无参数类继承的问题 先看一段示例代码,实现B继承于A: ? function?A()?{} ? A.prototype.a1?=?function()?{}; ? function?B()?{} ? B.prototype?=?new?A(); ? B.prototype.b1?=?function()?{}; ? var?b?=?new?B(); ? alert(b.constructor?==?A);?//?true ? alert(b.constructor?==?B);?//?false?? 这段代码的主要问 题是: 1、需要实例化A作为B的原型,此时就执行了A的构造函数。但按照面向对象的规则,实例化B之前,B及其父类A的构造函数都不应该执行。 2、更改了B的prototype,导致b.constructor不是B而是A。 有参类继承的问题 假设A和B都有两个字符串参数s1和s2,A中计算了两段字符串的总长度,B直接以s1、s2为参数调用A: function?A(s1,?s2)? ? { ? this.totalLength?=?s1.length?+?s2.length; ? } ? A.prototype.a1?=?function()? ? { ? }; ? function?B(s1,?s2)? ? { ? } ? B.prototype?=?new?A(); ? B.prototype.b1?=?function()? ? { ? }; ? new?B(“ab”,?“123″);?? 可以看到,这段代码中根本没有办法把s1和s2传到A,而又因为实例化A作为B的原型时没有 参数,所以出现了异常:s1?is?undefined? ? 解决方案 s1 和s2的作用域只在B内,要把它们传到A,就只能在B中操作,借助函数的apply方法就可以实现之: function?B(s1,?s2)? ? { ? A.apply(this,?arguments); ? alert(this.totalLength); ? } ? ? ? ? ? ?
部分出处:http://developer.51cto.com/art/200907/134911.htm http://developer.51cto.com/art/201105/264432.htm http://developer.51cto.com/art/200907/134909.htm ?
parseInt("11",10); //返回 11 (10+1)
parseInt("11",2); //返回 3 (2+1)
parseInt("11",8); //返回?9 (8+1)
parseInt("11",16); //返回?17 (16+1)
parseInt("010");???????????????//返回10或8
?
?