ppk on javascript 笔记(五)
第5章 核心
1999年ECMA将核心标准化为ecmascript(http://www.ecma-international.org/publications/standards/Ecma-262.htm),对该规范最重要的评论来自Douglas Crockford(http://crockford.com/javascript/recommend.html)关于Crockford更多的文章可参考(http://dancewithnet.com/2009/03/29/douglas-crockford/)
基础知识
区分大小写
语句和分号:分号表示一条语句结束;对于一行代码的语句,不管是否以分号结尾,javascript会自动插入分号;当使用if,for或while控制结构时,可以不用分号结束。
注释
代码块:{};当if, while, for只包含一条语句时,可以省略{};函数主体必须在{}中。
运算符:优先级;返回值;赋值运算符返回当前的值,因此可以使用var a=b=1;
值:函数也可以用来赋值(注意使用为值时不应该再带括号)。
数据类型
javascript有4种重要的数据类型:数字、字符串、布尔型和对象;4种小数据类型:undefined、null以及表示“不存在”的两种说法。
null意味着无值,下面不会报错,显示为null,但当我们使用null值时就会报错--缺少对象。
alert(x);
undefined发生在3种情况:声明了一个变量,但没有赋值;访问一个对象尚未声明的属性;定义了函数的参数,但没有传值给它。
alert(window.y);
第一条语句会报错:y未定义;第二行和第三行则会显示undefined。
typeof运算符表示一个值的数据类型,它有两个特例:
var y ='1'; alert(typeof y);
var z =true; alert(typeof z);
function f() {}
alert(typeof(f));
alert(typeof(null));
第一行返回number,第二行返回string,第三行返回boolean。
函数使用typeof时返回function,null则返回object。
数据类型转换:javascript会根据需要将一种类型解释为另一种类型,原类型并没有改变。如:
var b ='3';
var c = a * b;
a是一个数字,b是一个字符串,在做乘法运算时,将b解释为数字,结果c是一个数字,值为6,b并没有改变,仍是一个字符串。
上面的alert(x),实际上也是把null解释为字符串,然后输出。
当字符串不能被解释为数字时,返回NaN.
使用+时,总是解释为连接,而不是加法运算。
转换为布尔型时,null, undefine, 数字0, NaN, 空字符串''被转换为false,其他所有的值被转换为true。
显式的数据类型转换,如:x1或者-0将字符串转换成数字,+''将转换成字符串,使用!!转换成布尔型。
普通运算符
* - / %及*=等,++和--同样区分前后,=赋值运算符返回被赋予的值,==相等运算符,===等同运算符要求数据类型一致,同样!==不等同运算符也针对数据类型。
比较运算符总是先将变量解释为数字进行比较,若有一个不能解释为数字,则按照第一个字母顺序进行比较,后面的大于前面的,小写的大于大写的(类似ascii)
条件运算符?:
变量
变量命名习惯采用低驼峰命名规则(lowerCamelCase),W3CDOM也如此命名,命名时不要使用保留字。
允许对一个未声明的变量直接赋值,这个变量会自动声明,但不允许直接使用未声明的变量,最好使用var显示声明以保持代码清晰。
按作用域分为全局变量和局部变量,没有块作用域,当在函数体中用var显式声明或作为函数的参数时为局部变量,其他情况如在函数体内未用var声明而直接使用或在函数体外声明的都是全局变量,尽量使用局部变量。
处理数字
不区分整数和浮点数,在使用浮点数时会产生舍入误差的bug,因此浮点数运算的结果在显示之前要先进行舍入。0.5可以简写为.5s
以0开头的数字为8进制,以0x开头的数字为16进制。
Math对象:
取整的三种方法:Math.round(), Math.floor(), Math.ceil(),同样适用于负数;
Math.random()用于产生0~1的随机数;
Math.abs()取绝对值。
n.toFixed(2)将数字n转换成一个拥有固定位数的字符串,要求n必须为number类型,否则会报错;它返回字符串。
全局方法parseInt(x)和parseFloat(x)将字符串转换为数字,它逐字符检查字符串,直接遇见非数字字符为止,当第一个字符非数字时才返回NaN,而上面的显式转换则要求字符串必须全部为数字,(注意16进制的x和float的.也是允许的)。
与字符串打交道
习惯上适用单引号表示字符串,允许使用双引号,\为转义符,+为连接符。
x.length用于取字符串的长度,这是字符串对象的一个属性,且是只读的。
x.indexOf('a')和x.lastIndexOf('a')用于检索,它返回的索引从0开始,未检索到时返回-1,可以指定检索开始的位置,如x.indexOf('a', 2), x.lastIndexOf('a', x.length-1)。
x.charAt(9)返回指定位置的字符,索引从0开始。
x.substring(9)或x.substring(9, 11)返回开始位置和结束位置之间的字符串,索引从0开始。
x.split('c')用指定的分隔符将字符串转换为数组,分隔符本身并不出现。
x.toLowerCase()和x.toUpperCase()用于大小写转换。
处理布尔值
布尔型数据只有两个:true和false。
逻辑运算符|| && !,注意javascript也包含逐位运算符&和|。
if(!document.styleSheets)对象检测时,若浏览器不支持这种方法,即为一个不存在的对象null,它被转换为false。
逻辑运算符||和&&并不返回布尔值,而是返回运算中最后一次计算的表达式的值。
例如,应用这个方法,我们可以使用来取得事件目标
大多数的浏览器将事件目标保存在evt.target中,而IE保存在srcElement中,当evt.target非null时,则返回,否则继续计算srcElement。&&用法也如此。
控制结构
if ... else if ... else ...
switch(...) { case ..: .. break; default:... } 注意,switch允许任意的数据类型(其他语言如java只允许对数字),但switch与case比较时,不会进行数据类型的转换。
四种循环语句:for, while, do/while, for in
for, while 条件检测总在循环体执行之前,而do/while先执行后检测。
当while陷入无限循环时,浏览器会提示是否终止代码运行。
do { ...} while(..); 最好在do/while的最后加一个分号。
break与continue。
当在嵌套循环中想跳出外层循环时,使用标签是可行的,事实上,任何语句都可以标志为标签。
for(var j=0; j<x.length; j++) {
if([something is the case]) continue myloop;
}
}
try/catch用来确保用户不会看到错误信息。
函数
定义一个函数 function f() {} 或 var f = function() {}。
函数可以直接return;或return任意一个数据类型。
var g=f; 则定义了函数的一个引用,可以运行g();。
当将函数作为一个值时不能使用(),而()运算符则命令函数执行。
函数可以内嵌函数,使用内嵌函数时,需注意局部变量的作用域:
var message =' clicked ';
var x = document.getElementsByTagName('a');
for (var i=0; i<x.length; i++) {
x[i].onclick =function() {
x[i].firstChild.nodeValue = message;
}
}
}
函数运行在被定义的作用域中,而不是执行它们的作用域中。这意味着内嵌函数可以访问所有它的父函数的局部变量,即使父函数在内嵌函数调用前就早已执行。
在此,内嵌函数访问了父函数的局部变量i和x,但是i发生了错误,程序报错。这是因为内嵌函数只能访问到局部变量的最终值;
假设x.length=9,那么init函数执行结束后i的值为10,以后当内嵌函数触发时就会使用这个i,于是使用了x[10]这个null值,从而报错;
正确的写法应该是 x[i].onclick = function() { this.firstchild.nodeValue = message; }
对象
对象用来保存彼此相关联的变量和函数,也就是一组属性的集合,值为函数的属性称作方法,点运算符用来获取一个属性或方法。
允许自定义对象 var t = new Object(); t.a = 1; t.b = function() {}
可以用字面量来定义对象 var t = { a:1, b:fucntion() {} }属性间用逗号隔开。
访问一个属性没有什么害处,不管对象是否有这个属性,但是访问一个方法的同时也尝试去执行它,例如
if(e.stopPropagation) {
e.stopPropagation();
}
e.cancelBubble =true;
}
对停止事件传播,W3C标准的浏览器需执行stopPropagation方法,而IE只需将cancelBubble设为true,上面这种写法是规范的,直接访问不存在的方法会报错,而对于W3C标准的浏览器则只是多创建一个值为true的属性而已,但是这个属性对IE来说却是一个预定义属性,改变预定义属性的值便会引起一些相应的动作。
允许创建自己的属性。
this关键字出现在方法中(js不区分方法和函数),用来引用定义该方法的对象。
属性和变量也是对等不区分的,全局变量也即全局对象window的属性。
关联数组
下面两种表达式等价的:object.property; object['property']; 同样的这也是等价的:object.method(); object['method']();
使用点符号时,后面的属性名或方法名是固定的字符串常量,而使用方括号则可以使用变量随意更改属性的名字。
关联数组是一个数组,它允许通过字符串作为值的名字来找到某一个确定的值,这些字符串叫做关键字。
for in用来遍历一个关联数组,例如
a:2,
b:'2',
c:function() {
alert(this.a*this.b);
}
}
for(var i in t) {
alert(i +':'+ t[i]);
}
弹出的三个信息分别为a:2,b:2和c:fuction() { alert(this.a*this.b); }。注意到i表示了关键字,而方括号使用了变量i来获取t的属性(点符号是行不通的,t.i表示t的i属性),同时也可以看到a的值数字2被转换成了字符串2。
数组
数组是一个用数字来索引的值的集合,索引数从0开始,例如
t[0] ='2';
t[2] =3;
t[5] =function() {
alert(this[0] *this[2]);
}
t[5]();
alert(t[1]);
这定义了一个稀疏数组,它只定义了几个元素,对于其他元素根本就没有创建它们,访问时会返回undefined,就好像一个未定义的属性一样。运行t[5]()会弹出6。t[7]则是一个嵌套数组。
除了上述定义方法,数组还有两种表示法:
var t = [0, 1, '2', 'three', false];
这两种方法无法指定特定的索引序列,其中后一种方法数组字面量常用。
如getElementsByTagName获得的节点列表并不是数组,可以看做为缺乏所有定义在数组对象上的有用方法的只读数组,以后再介绍。
length属性表示数组长度,数组长度总是最大的索引数加1,包括稀疏数组。增加减少元素会更新length的值,对length属性赋值会改变数组,访问超出长度的索引会返回undefined。
设t是一个数组,有四种方法增减元素:t.unshift(x);用来插入一个起始元素,t.shift();删除一个起始元素,t.push(x)插入一个末尾元素,t.pop()删除一个末尾元素。