JavaScript简介
区分大小写
ECMAScript中的一切(变量、函数名和操作符)都区分大小写。
标识符
指变量、函数、属性的名字,或者函数的参数。标识符可以是按照下列格式规则 组合起来的一或多个字符:
- 第一个字符必须是一个字母、下划线(_)或一个美元符号($);
- 其他字符可以是字母、下划线、美元符号或数字。
ECMAScript 标识符采用驼峰大小写格式,也就是第一个字母小写,剩下的每个单词的 首字母大写
不能把关键字、保留字、true、false 和null 用作标识符。
注释
ECMAScript使用 C风格的注释,包括单行注释和块级注释。单行注释以两个斜杠开头,如下所示:
// 单行注释
块级注释以一个斜杠和一个星号(/)开头,以一个星号和一个斜杠(/)结尾,如下所示:
/*
这是一个多行
(块级)注释
*/
严格模式
ECMAScript 5引入了严格模式(strict mode)的概念。严格模式是为 JavaScript定义了一种不同的 解析与执行模型。在严格模式下,ECMAScript 3中的一些不确定的行为将得到处理,而且对某些不安全 的操作也会抛出错误。要在整个脚本中启用严格模式,可以在顶部添加如下代码:
"use strict";
这行代码看起来像是字符串,而且也没有赋值给任何变量,但其实它是一个编译指示(pragma), 用于告诉支持的 JavaScript引擎切换到严格模式。这是为不破坏 ECMAScript 3语法而特意选定的语法。
在函数内部的上方包含这条编译指示,也可以指定函数在严格模式下执行:
function doSomething(){
"use strict";
//函数体
}
严格模式下,JavaScript 的执行结果会有很大不同,因此本书将会随时指出严格模式下的区别。
语句
ECMAScript中的语句以一个分号结尾;
关键字和保留字
ECMA-262描述了一组具有特定用途的关键字,这些关键字可用于表示控制语句的开始或结束,或 者用于执行特定操作等。按照规则,关键字也是语言保留的,不能用作标识符。以下就是 ECMAScript 的全部关键字(带*号上标的是第 5版新增的关键字):
break do instanceof typeof case
else new var catch finally
return void continue for switch
while debugger* function this with default
if throw delete in try
ECMA-262还描述了另外一组不能用作标识符的保留字。尽管保留字在这门语言中还没有任何特定 的用途,但它们有可能在将来被用作关键字。以下是 ECMA-262第 3版定义的全部保留字:
abstract enum int short boolean export interface static byte
extends long super char final native synchronized class float
package throws const goto private transient debugger implements protected
volatile double import public
第 5版把在非严格模式下运行时的保留字缩减为下列这些:
class enum extends super const export import
在严格模式下,第 5版还对以下保留字施加了限制:
implements package public interface private static let protected yield
变量
ECMAScript 的变量是松散类型的,所谓松散类型就是可以用来保存任何类型的数据。定义变量时要使用 var 操作符,后跟变量名,如下所示:
var message;
这行代码定义了一个名为 message 的变量,该变量可以用来保存任何值。ECMAScript也支持直接初始 化变量,因此在定义变量的同时就可以设置变量的值,如下所示:
var message = "hi";
像这样初始化变量并不会把它标记为字符串类型; 初始化的过程就是给变量赋一个值那么简单。因此,可以在修改变量值的同时修改值的类型,如下所示:
var message = "hi"; message = 100; // 有效,但不推荐
用 var 操作符定义的变量将成为定义该变量的作用域中的局部变量。也就是说, 如果在函数中使用 var 定义一个变量,那么这个变量在函数退出后就会被销毁,例如:
function test(){
var message = "hi"; // 局部变量
}
test();
alert(message); // 错误!
这里,变量 message 是在函数中使用 var 定义的。当函数被调用时,就会创建该变量并为其赋值。 而在此之后,这个变量又会立即被销毁,因此例子中的下一行代码就会导致错误。不过,可以像下面这 样省略 var 操作符,从而创建一个全局变量:
function test(){
message = "hi"; // 全局变量
}
test();
alert(message); // "hi"
这个例子省略了 var 操作符,因而 message 就成了全局变量。这样,只要调用过一次 test()函 数,这个变量就有了定义,就可以在函数外部的任何地方被访问到。
虽然省略 var 操作符可以定义全局变量,但这也不是我们推荐的做法。因为在局 部作用域中定义的全局变量很难维护,而且如果有意地忽略了 var 操作符,也会由于 相应变量不会马上就有定义而导致不必要的混乱。给未经声明的变量赋值在严格模式 下会导致抛出 ReferenceError 错误。
可以使用一条语句定义多个变量,只要像下面这样把每个变量(初始化或不初始化均可)用逗号分 隔开即可:
var message = "hi",
found = false,
age = 29;
这个例子定义并初始化了 3个变量。同样由于 ECMAScript是松散类型的,因而使用不同类型初始 化变量的操作可以放在一条语句中来完成。虽然代码里的换行和变量缩进不是必需的,但这样做可以提 高可读性。
数据类型
ECMAScript中有 5种简单数据类型(也称为基本数据类型):Undefined、Null、Boolean、Number 和String。还有1种复杂数据类型——Object,Object 本质上是由一组无序的名值对组成的。ECMAScript 不支持任何创建自定义类型的机制,而所有值终都将是上述 6种数据类型之一。乍一看,好像只有 6 种数据类型不足以表示所有数据;但是,由于 ECMAScript数据类型具有动态性,因此的确没有再定义 其他数据类型的必要了。
typeof操作符
鉴于 ECMAScript 是松散类型的,因此需要有一种手段来检测给定变量的数据类型——typeof 就 是负责提供这方面信息的操作符。对一个值使用 typeof 操作符可能返回下列某个字符串:
- "undefined"——如果这个值未定义;
- "boolean"——如果这个值是布尔值;
- "string"——如果这个值是字符串;
- "number"——如果这个值是数值;
- "object"——如果这个值是对象或 null;
- "function"——如果这个值是函数。
Undefined类型
Undefined 类型只有一个值,即特殊的 undefined。在使用 var 声明变量但未对其加以初始化时, 这个变量的值就是 undefined,例如:
var message;
alert(message == undefined); //true
Null类型
Null 类型是第二个只有一个值的数据类型,这个特殊的值是 null。从逻辑角度来看,null 值表 示一个空对象指针,而这也正是使用 typeof 操作符检测 null 值时会返回"object"的原因,如下面 的例子所示:
var car = null;
alert(typeof car); // "object"
Boolean类型 Boolean 类型是 ECMAScript中使用得多的一种类型,该类型只有两个字面值:true 和 false。 这两个值与数字值不是一回事,因此 true 不一定等于 1,而 false 也不一定等于 0。以下是为变量赋 Boolean 类型值的例子:
var found = true;
var lost = false;
需要注意的是,Boolean 类型的字面值 true 和 false 是区分大小写的。也就是说,True 和 False (以及其他的混合大小写形式)都不是 Boolean 值,只是标识符。 虽然 Boolean 类型的字面值只有两个,但 ECMAScript中所有类型的值都有与这两个 Boolean 值 等价的值。要将一个值转换为其对应的 Boolean 值,可以调用转型函数 Boolean(),如下例所示:
var message = "Hello world!";
var messageAsBoolean = Boolean(message);
在这个例子中,字符串 message 被转换成了一个 Boolean 值,该值被保存在 messageAsBoolean 变量中。可以对任何数据类型的值调用 Boolean()函数,而且总会返回一个 Boolean 值。至于返回的 这个值是 true 还是 false,取决于要转换值的数据类型及其实际值。下表给出了各种数据类型及其对 应的转换规则。
数据类型 | 转换为true的值 | 转换为false的值 |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | ""(空字符串) |
Number | 任何非零数字值(包括无穷大) | 0 和NaN |
Object | 任何对象 | null |
Undefined | n/a① | undefined |
① n/a(或 N/A),是 not applicable的缩写,意思是“不适用”。
Number类型
基本的数值字面量格式是十进制整数。
除了以十进制表示外,整数还可以通过八进制(以 8为基数)或十六进制(以 16 为基数)的字面值 来表示。其中,八进制字面值的第一位必须是零(0),然后是八进制数字序列(0~7)。如果字面值中的 数值超出了范围,那么前导零将被忽略,后面的数值将被当作十进制数值解析。八进制字面量在严格模式下是无效的,会导致支持的 JavaScript引擎抛出错误。
十六进制字面值的前两位必须是 0x,后跟任何十六进制数字(0~9 及 A~F)。其中,字母 A~F 可以大写,也可以小写。
鉴于 JavaScript中保存数值的方式,可以保存正零(+0)和负零(-0)。正零和负零被认为相等
-
浮点数值
所谓浮点数值,就是该数值中必须包含一个小数点,并且小数点后面必须至少有一位数字。
var floatNum1 = 1.1;
var floatNum2 = 0.1;
var floatNum3 = .1; // 有效,但不推荐
对于那些极大或极小的数值,可以用 e表示法(即科学计数法)表示的浮点数值表示。用 e表示法 表示的数值等于 e前面的数值乘以 10的指数次幂。ECMAScript中 e表示法的格式也是如此,即前面是 一个数值(可以是整数也可以是浮点数),中间是一个大写或小写的字母 E,后面是 10的幂中的指数, 该幂值将用来与前面的数相乘。
浮点数值的高精度是 17位小数,但在进行算术计算时其精确度远远不如整数。
-
数值范围
由于内存的限制,ECMAScript并不能保存世界上所有的数值。ECMAScript能够表示的小数值保 存在 Number.MIN_VALUE 中——在大多数浏览器中,这个值是 5e-324;能够表示的大数值保存在 Number.MAX_VALUE 中——在大多数浏览器中,这个值是 1.7976931348623157e+308。如果某次计算的 结果得到了一个超出 JavaScript数值范围的值,那么这个数值将被自动转换成特殊的 Infinity 值。具 体来说,如果这个数值是负数,则会被转换成-Infinity(负无穷),如果这个数值是正数,则会被转 换成 Infinity(正无穷)。
如上所述,如果某次计算返回了正或负的 Infinity 值,那么该值将无法继续参与下一次的计算, 因为 Infinity 不是能够参与计算的数值。
-
NaN
NaN,即非数值(Not a Number)是一个特殊的数值,这个数值用于表示一个本来要返回数值的操作数 未返回数值的情况(这样就不会抛出错误了)。例如,在其他编程语言中,任何数值除以 0都会导致错误, 从而停止代码执行。但在ECMAScript中,任何数值除以 0会返回 NaN,因此不会影响其他代码的执行。 NaN 本身有两个非同寻常的特点。首先,任何涉及 NaN 的操作(例如 NaN/10)都会返回 NaN,这 个特点在多步计算中有可能导致问题。其次,NaN 与任何值都不相等,包括 NaN 本身。
针对 NaN 的这两个特点,ECMAScript定义了 isNaN()函数。这个函数接受一个参数,该参数可以 是任何类型,而函数会帮我们确定这个参数是否“不是数值”。
- 数值转换
有 3个函数可以把非数值转换为数值:Number()、parseInt()和 parseFloat()。第一个函数, 即转型函数 Number()可以用于任何数据类型,而另两个函数则专门用于把字符串转换成数值。这 3个 函数对于同样的输入会有返回不同的结果。 Number()函数的转换规则如下。
如果是 Boolean 值,true 和 false 将分别被转换为 1和 0。
如果是数字值,只是简单的传入和返回。
如果是 null 值,返回 0。
如果是 undefined,返回 NaN。
-
如果是字符串,遵循下列规则:
- 如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即"1" 会变成 1,"123"会变成 123,而"011"会变成 11(注意:前导的零被忽略了);
- 如果字符串中包含有效的浮点格式,如"1.1",则将其转换为对应的浮点数值(同样,也会忽 略前导零);
- 如果字符串中包含有效的十六进制格式,例如"0xf",则将其转换为相同大小的十进制整 数值;
- 如果字符串是空的(不包含任何字符),则将其转换为 0;
- 如果字符串中包含除上述格式之外的字符,则将其转换为 NaN。
如果是对象,则调用对象的 valueOf()方法,然后依照前面的规则转换返回的值。如果转换 的结果是 NaN,则调用对象的 toString()方法,然后再次依照前面的规则转换返回的字符 串值。
parseInt()函数在转换字符串时,更多的是看其是否符合数值模式。它会忽略字 符串前面的空格,直至找到第一个非空格字符。如果第一个字符不是数字字符或者负号,parseInt() 就会返回 NaN;也就是说,用 parseInt()转换空字符串会返回 NaN(Number()对空字符返回 0)。如 果第一个字符是数字字符,parseInt()会继续解析第二个字符,直到解析完所有后续字符或者遇到了 一个非数字字符。
与 parseInt()函数类似,parseFloat()也是从第一个字符(位置 0)开始解析每个字符。而且 也是一直解析到字符串末尾,或者解析到遇见一个无效的浮点数字字符为止。也就是说,字符串中的第 一个小数点是有效的,而第二个小数点就是无效的了,因此它后面的字符串将被忽略。
String类型
- 字符字面量
String 数据类型包含一些特殊的字符字面量,也叫转义序列,用于表示非打印字符,或者具有其 他用途的字符。这些字符字面量如下表所示:
字 面 量 | 含 义 |
---|---|
\n | 换行 |
\t | 制表 |
\b | 空格 |
\r | 回车 |
\f | 进纸 |
\ \ | 斜杠 |
\ ' | 单引号('),在用单引号表示的字符串中使用。例如:'He said, \ 'hey.\ ' ' |
\ " | 双引号("),在用双引号表示的字符串中使用。例如:"He said, \ "hey.\ " " |
\xnn | 以十六进制代码nn表示的一个字符(其中n为0~F)。例如,\x41表示"A" |
\unnnn | 以十六进制代码nnnn表示的一个Unicode字符(其中n为0~F)。例如,\u03a3表示希腊字符Σ |
- 转换为字符串
要把一个值转换为一个字符串有两种方式。第一种是使用几乎每个值都有的 toString()方法。
在不知道要转换的值是不是 null 或 undefined 的情况下,还可以使用转型函数 String(),这个 函数能够将任何类型的值转换为字符串。String()函数遵循下列转换规则:
- 如果值有 toString()方法,则调用该方法(没有参数)并返回相应的结果;
- 如果值是 null,则返回"null";
- 如果值是 undefined,则返回"undefined"。
Object类型
ECMAScript中的对象其实就是一组数据和功能的集合。对象可以通过执行 new 操作符后跟要创建 的对象类型的名称来创建。而创建 Object 类型的实例并为其添加属性和(或)方法,就可以创建自定 义对象,如下所示:
var o = new Object();
Object 类型是所有它的实例的基础。换句话说, Object 类型所具有的任何属性和方法也同样存在于更具体的对象中。 Object 的每个实例都具有下列属性和方法。
- constructor:保存着用于创建当前对象的函数。对于前面的例子而言,构造函数(constructor) 就是 Object()。
- hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而不是在实例 的原型中)是否存在。其中,作为参数的属性名(propertyName)必须以字符串形式指定(例 如:o.hasOwnProperty("name"))。
- isPrototypeOf(object):用于检查传入的对象是否是传入对象的原型(第 5 章将讨论原 型) 。
- propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用 for-in 语句 (本章后面将会讨论)来枚举。与 hasOwnProperty()方法一样,作为参数的属性名必须以字符 串形式指定。
- toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
- toString():返回对象的字符串表示。 valueOf():返回对象的字符串、数值或布尔值表示。通常与 toString()方法的返回值 相同。
操作符
ECMA-262 描述了一组用于操作数据值的操作符,包括算术操作符(如加号和减号)、位操作符、 关系操作符和相等操作符。ECMAScript 操作符的与众不同之处在于,它们能够适用于很多值,例如字 符串、数字值、布尔值,甚至对象。不过,在应用于对象时,相应的操作符通常都会调用对象的 valueOf() 和(或)toString()方法,以便取得可以操作的值。
一元操作符
1. 递增和递减操作符 ++age; --age;
- 在应用于一个包含有效数字字符的字符串时,先将其转换为数字值,再执行加减 1 的操作。字 符串变量变成数值变量。
- 在应用于一个不包含有效数字字符的字符串时,将变量的值设置为 NaN(第 4章将详细讨论)。 字符串变量变成数值变量。
- 在应用于布尔值 false 时,先将其转换为 0再执行加减 1的操作。布尔值变量变成数值变量。
- 在应用于布尔值 true 时,先将其转换为 1再执行加减 1的操作。布尔值变量变成数值变量。
- 在应用于浮点数值时,执行加减 1的操作。
- 在应用于对象时,先调用对象的 valueOf()方法以取得一个可供操作的 值。然后对该值应用前述规则。如果结果是 NaN,则在调用 toString()方法后再应用前述规 则。对象变量变成数值变量。
2. 一元加和减操作符 + -
位操作符
按位非(NOT) ~
按位与(AND) &
按位或(OR) |
按位异或(XOR) ^
左移 <<
有符号的右移 >>
无符号右移 >>>
布尔操作符
-
逻辑非
逻辑非操作符由一个叹号(!)表示,可以应用于 ECMAScript中的任何值。无论这个值是什么数据 类型,这个操作符都会返回一个布尔值。逻辑非操作符首先会将它的操作数转换为一个布尔值,然后再 对其求反。也就是说,逻辑非操作符遵循下列规则:
- 如果操作数是一个对象,返回 false;
- 如果操作数是一个空字符串,返回 true;
- 如果操作数是一个非空字符串,返回 false;
- 如果操作数是数值 0,返回 true;
- 如果操作数是任意非 0数值(包括 Infinity),返回 false;
- 如果操作数是 null,返回 true;
- 如果操作数是 NaN,返回 true;
- 如果操作数是 undefined,返回 true。
-
逻辑与
逻辑与操作符由两个和号(&&)表示,有两个操作数
逻辑与操作可以应用于任何类型的操作数,而不仅仅是布尔值。在有一个操作数不是布尔值的情况 下,逻辑与操作就不一定返回布尔值;此时,它遵循下列规则:
- 如果第一个操作数是对象,则返回第二个操作数;
- 如果第二个操作数是对象,则只有在第一个操作数的求值结果为 true 的情况下才会返回该 对象;
- 如果两个操作数都是对象,则返回第二个操作数;
- 如果有一个操作数是 null,则返回 null;
- 如果有一个操作数是 NaN,则返回 NaN;
- 如果有一个操作数是 undefined,则返回 undefined。
-
逻辑或
逻辑或操作符由两个竖线符号(||)表示,有两个操作数
与逻辑与操作相似,如果有一个操作数不是布尔值,逻辑或也不一定返回布尔值;此时,它遵循下 列规则:
- 如果第一个操作数是对象,则返回第一个操作数;
- 如果第一个操作数的求值结果为 false,则返回第二个操作数;
- 如果两个操作数都是对象,则返回第一个操作数;
- 如果两个操作数都是 null,则返回 null;
- 如果两个操作数都是 NaN,则返回 NaN;
- 如果两个操作数都是 undefined,则返回 undefined。
乘性操作符
-
乘法
乘法操作符由一个星号(*)表示,用于计算两个数值的乘积。
在处理特殊值的情况下,乘法操作符遵循下列特殊的规则:
- 如果操作数都是数值,执行常规的乘法计算,即两个正数或两个负数相乘的结果还是正数,而 如果只有一个操作数有符号,那么结果就是负数。如果乘积超过了 ECMAScript数值的表示范围, 则返回 Infinity 或-Infinity;
- 如果有一个操作数是 NaN,则结果是 NaN;
- 如果是 Infinity 与 0相乘,则结果是 NaN;
- 如果是 Infinity 与非 0数值相乘,则结果是 Infinity 或-Infinity,取决于有符号操作数 的符号;
- 如果是 Infinity 与 Infinity 相乘,则结果是 Infinity;
- 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的 规则。
-
除法
除法操作符由一个斜线符号(/)表示,执行第二个操作数除第一个操作数的计算 与乘法操作符类似,除法操作符对特殊的值也有特殊的处理规则。这些规则如下:
- 如果操作数都是数值,执行常规的除法计算,即两个正数或两个负数相除的结果还是正数,而 如果只有一个操作数有符号,那么结果就是负数。如果商超过了 ECMAScript数值的表示范围, 则返回 Infinity 或-Infinity;
- 如果有一个操作数是 NaN,则结果是 NaN;
- 如果是 Infinity 被 Infinity 除,则结果是 NaN;
- 如果是零被零除,则结果是 NaN;
- 如果是非零的有限数被零除,则结果是 Infinity 或-Infinity,取决于有符号操作数的符号;
- 如果是 Infinity 被任何非零数值除,则结果是 Infinity 或-Infinity,取决于有符号操作 数的符号;
- 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。
-
求模
求模(余数)操作符由一个百分号(%)表示
与另外两个乘性操作符类似,求模操作符会遵循下列特殊规则来处理特殊的值:
- 如果操作数都是数值,执行常规的除法计算,返回除得的余数;
- 如果被除数是无穷大值而除数是有限大的数值,则结果是 NaN;
- 如果被除数是有限大的数值而除数是零,则结果是 NaN;
- 如果是 Infinity 被 Infinity 除,则结果是 NaN;
- 如果被除数是有限大的数值而除数是无穷大的数值,则结果是被除数;
- 如果被除数是零,则结果是零;
- 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。
加性操作符
加法和减法这两个加性操作符应该说是编程语言中简单的算术操作符了。但是在 ECMAScript中, 这两个操作符却都有一系列的特殊行为。与乘性操作符类似,加性操作符也会在后台转换不同的数据类 型。然而,对于加性操作符而言,相应的转换规则还稍微有点复杂。
-
加法
加法操作符(+)
如果两个操作符都是数值,执行常规的加法计算,然后根据下列规则返回结果:
- 如果有一个操作数是 NaN,则结果是 NaN;
- 如果是 Infinity 加 Infinity,则结果是 Infinity;
- 如果是-Infinity 加-Infinity,则结果是-Infinity;
- 如果是 Infinity 加-Infinity,则结果是 NaN;
- 如果是+0加+0,则结果是+0;
- 如果是-0加-0,则结果是-0;
- 如果是+0加-0,则结果是+0。
不过,如果有一个操作数是字符串,那么就要应用如下规则:
- 如果两个操作数都是字符串,则将第二个操作数与第一个操作数拼接起来;
- 如果只有一个操作数是字符串,则将另一个操作数转换为字符串,然后再将两个字符串拼接 起来。
如果有一个操作数是对象、数值或布尔值,则调用它们的 toString()方法取得相应的字符串值, 然后再应用前面关于字符串的规则。对于 undefined 和 null,则分别调用 String()函数并取得字符 串"undefined"和"null"。 以上代码演示了加法操作符在两种模式下的差别。第一行代码演示了正常的情况,即 5+5 等于 10 (数值)。但是,如果将一个操作数改为字符串"5",结果就变成了"55"(字符串值),因为第一个操作 数也被转换成了"5"。 忽视加法操作中的数据类型是 ECMAScript编程中常见的一个错误。
-
减法
减法操作符(-)是另一个极为常用的操作符
与加法操作符类似,ECMAScript 中的减法操作符在处理各种数据类型转换时,同样需要遵循一些 特殊规则,如下所示:
- 如果两个操作符都是数值,则执行常规的算术减法操作并返回结果;
- 如果有一个操作数是 NaN,则结果是 NaN;
- 如果是 Infinity 减 Infinity,则结果是 NaN;
- 如果是-Infinity 减-Infinity,则结果是 NaN;
- 如果是 Infinity 减-Infinity,则结果是 Infinity;
- 如果是-Infinity 减 Infinity,则结果是-Infinity;
- 如果是+0减+0,则结果是+0;
- 如果是+0减-0,则结果是-0;
- 如果是-0减-0,则结果是+0;
- 如果有一个操作数是字符串、布尔值、null 或 undefined,则先在后台调用 Number()函数将 其转换为数值,然后再根据前面的规则执行减法计算。如果转换的结果是 NaN,则减法的结果 就是 NaN;
- 如果有一个操作数是对象,则调用对象的 valueOf()方法以取得表示该对象的数值。如果得到 的值是 NaN,则减法的结果就是 NaN。如果对象没有 valueOf()方法,则调用其 toString() 方法并将得到的字符串转换为数值。
关系操作符
小于(<)、大于(>)、小于等于(<=)和大于等于(>=)
与 ECMAScript中的其他操作符一样,当关系操作符的操作数使用了非数值时,也要进行数据转换 或完成某些奇怪的操作。以下就是相应的规则。
- 如果两个操作数都是数值,则执行数值比较。
- 如果两个操作数都是字符串,则比较两个字符串对应的字符编码值。
- 如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较。
- 如果一个操作数是对象,则调用这个对象的 valueOf()方法,用得到的结果按照前面的规则执 行比较。如果对象没有 valueOf()方法,则调用 toString()方法,并用得到的结果根据前面 的规则执行比较。
- 如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较。
相等操作符
确定两个变量是否相等是编程中的一个非常重要的操作。在比较字符串、数值和布尔值的相等性时, 问题还比较简单。但在涉及到对象的比较时,问题就变得复杂了。早的 ECMAScript中的相等和不等 操作符会在执行比较之前,先将对象转换成相似的类型。后来,有人提出了这种转换到底是否合理的质 疑。后,ECMAScript 的解决方案就是提供两组操作符:相等和不相等——先转换再比较,全等和不 全等——仅比较而不转换。
-
相等和不相等
ECMAScript中的相等操作符由两个等于号(==)表示,如果两个操作数相等,则返回 true。而不 相等操作符由叹号后跟等于号(!=)表示,如果两个操作数不相等,则返回 true。这两个操作符都会 先转换操作数(通常称为强制转型),然后再比较它们的相等性。 在转换不同的数据类型时,相等和不相等操作符遵循下列基本规则:
- 如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false 转换为 0,而 true 转换为 1;
- 如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值;
- 如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法,用得到的基本类 型值按照前面的规则进行比较; 这两个操作符在进行比较时则要遵循下列规则。
- null 和 undefined 是相等的。
- 要比较相等性之前,不能将 null 和 undefined 转换成其他任何值。
- 如果有一个操作数是 NaN,则相等操作符返回 false,而不相等操作符返回 true。重要提示: 即使两个操作数都是 NaN,相等操作符也返回 false;因为按照规则,NaN 不等于 NaN。
- 如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象, 则相等操作符返回 true;否则,返回 false。
-
全等和不全等
除了在比较之前不转换操作数之外,全等和不全等操作符与相等和不相等操作符没有什么区别。全 等操作符由 3个等于号(===)表示,它只在两个操作数未经转换就相等的情况下返回 true。
由于相等和不相等操作符存在类型转换问题,而为了保持代码中数据类型的完整 性,我们推荐使用全等和不全等操作符。
条件操作符
条件操作符应该算是 ECMAScript中灵活的一种操作符了,而且它遵循与 Java中的条件操作符相 同的语法形式,如下面的例子所示:
variable = boolean_expression ? true_value : false_value;
赋值操作符
简单的赋值操作符由等于号(=)表示,其作用就是把右侧的值赋给左侧的变量
每个主要算术操作符(以及个别的其他操作符)都有对应的复合赋值操作符。这些操作符如下所示:
- 乘/赋值(*=);
- 除/赋值(/=);
- 模/赋值(%=);
- 加/赋值(+=);
- 减/赋值(-=);
- 左移/赋值(<<=);
- 有符号右移/赋值(>>=);
- 无符号右移/赋值(>>>=)。
设计这些操作符的主要目的就是简化赋值操作。使用它们不会带来任何性能的提升。
逗号操作符
使用逗号操作符可以在一条语句中执行多个操作
语句
1.if语句
大多数编程语言中为常用的一个语句就是 if 语句。以下是 if 语句的语法:
if (condition) statement1 else statement2
其中的 condition(条件)可以是任意表达式;而且对这个表达式求值的结果不一定是布尔值。 ECMAScript会自动调用 Boolean()转换函数将这个表达式的结果转换为一个布尔值。如果对 condition 求值的结果是true,则执行statement1(语句1),如果对condition求值的结果是false,则执行statement2 (语句 2)。而且这两个语句既可以是一行代码,也可以是一个代码块(以一对花括号括起来的多行代码)。
2.do-while语句
do-while 语句是一种后测试循环语句,即只有在循环体中的代码执行之后,才会测试出口条件。 换句话说,在对条件表达式求值之前,循环体内的代码至少会被执行一次。以下是 do-while 语句的 语法:
do {
statement
} while (expression);
3.while语句
while 语句属于前测试循环语句,也就是说,在循环体内的代码被执行之前,就会对出口条件求值。 因此,循环体内的代码有可能永远不会被执行。以下是 while 语句的语法:
while(expression) statement
4.for语句
for 语句也是一种前测试循环语句,但它具有在执行循环之前初始化变量和定义循环后要执行的代 码的能力。以下是 for 语句的语法:
for (initialization; expression; post-loop-expression) statement
5.for-in语句
for-in 语句是一种精准的迭代语句,可以用来枚举对象的属性。以下是 for-in 语句的语法:
for (property in expression) statement
下面是一个示例:
for (var propName in window) {
document.write(propName);
}
在这个例子中,我们使用 for-in 循环来显示了 BOM中 window 对象的所有属性。每次执行循环 时,都会将 window 对象中存在的一个属性名赋值给变量 propName。这个过程会一直持续到对象中的 所有属性都被枚举一遍为止。与 for 语句类似,这里控制语句中的 var 操作符也不是必需的。但是, 为了保证使用局部变量,我们推荐上面例子中的这种做法。
ECMAScript 对象的属性没有顺序。因此,通过 for-in 循环输出的属性名的顺序是不可预测的。 具体来讲,所有属性都会被返回一次,但返回的先后次序可能会因浏览器而异。
但是,如果表示要迭代的对象的变量值为 null 或 undefined,for-in 语句会抛出错误。 ECMAScript 5更正了这一行为;对这种情况不再抛出错误,而只是不执行循环体。为了保证大限度的兼容性,建议在使用 for-in 循环之前,先检测确认该对象的值不是 null 或 undefined。
6.label语句
使用 label 语句可以在代码中添加标签,以便将来使用。以下是 label 语句的语法:
label: statement
下面是一个示例:
start: for (var i=0; i < count; i++) {
alert(i);
}
这个例子中定义的 start 标签可以在将来由 break 或 continue 语句引用。加标签的语句一般都 要与 for 语句等循环语句配合使用。
7.break和continue语句
break 和 continue 语句用于在循环中精确地控制代码的执行。其中,break 语句会立即退出循环, 强制继续执行循环后面的语句。而 continue 语句虽然也是立即退出循环,但退出循环后会从循环的顶 部继续执行。
8.with语句
with 语句的作用是将代码的作用域设置到一个特定的对象中。with 语句的语法如下:
with (expression) statement;
定义 with 语句的目的主要是为了简化多次编写同一个对象的工作,如下面的例子所示:
var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;
上面几行代码都包含 location 对象。如果使用 with 语句,可以把上面的代码改写成如下所示:
with(location){
var qs = search.substring(1);
var hostName = hostname;
var url = href;
}
WithStatementExample01.htm
在这个重写后的例子中,使用 with 语句关联了 location 对象。这意味着在 with 语句的代码块 内部,每个变量首先被认为是一个局部变量,而如果在局部环境中找不到该变量的定义,就会查询 location 对象中是否有同名的属性。如果发现了同名属性,则以 location 对象属性的值作为变量的值。
严格模式下不允许使用 with 语句,否则将视为语法错误。
9.switch语句
switch 语句与 if 语句的关系为密切,而且也是在其他语言中普遍使用的一种流控制语句。 ECMAScript中 switch 语句的语法与其他基于 C的语言非常接近,如下所示:
switch (expression) {
case value: statement
break;
case value: statement
break;
case value: statement
break;
case value: statement
break;
default: statement
}
函数
函数对任何语言来说都是一个核心的概念。通过函数可以封装任意多条语句,而且可以在任何地方、 任何时候调用执行。ECMAScript中的函数使用 function 关键字来声明,后跟一组参数以及函数体。 函数的基本语法如下所示:
function functionName(arg0, arg1,...,argN) { statements }
严格模式对函数有一些限制:
- 不能把函数命名为 eval 或 arguments;
- 不能把参数命名为 eval 或 arguments;
- 不能出现两个命名参数同名的情况。
如果发生以上情况,就会导致语法错误,代码无法执行。
参数
ECMAScript函数的参数与大多数其他语言中函数的参数有所不同。ECMAScript函数不介意传递进 来多少个参数,也不在乎传进来参数是什么数据类型。也就是说,即便你定义的函数只接收两个参数, 在调用这个函数时也未必一定要传递两个参数。可以传递一个、三个甚至不传递参数,而解析器永远不 会有什么怨言。之所以会这样,原因是 ECMAScript中的参数在内部是用一个数组来表示的。函数接收 到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。如果这个数组中不包含任 何元素,无所谓;如果包含多个元素,也没有问题。实际上,在函数体内可以通过 arguments 对象来 访问这个参数数组,从而获取传递给函数的每一个参数。
严格模式对如何使用 arguments 对象做出了一些限制。首先,像前面例子中那样的赋值会变得无 效。也就是说,即使把 arguments[1]设置为 10,num2 的值仍然还是 undefined。其次,重写 arguments 的值会导致语法错误(代码将不会执行)。
ECMAScript中的所有参数传递的都是值,不可能通过引用传递参数。
没有重载
ECMAScript 函数不能像传统意义上那样实现重载。而在其他语言(如 Java)中,可以为一个函数 编写两个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可。如前所述,ECMAScirpt 函数没有签名,因为其参数是由包含零或多个值的数组来表示的。而没有函数签名,真正的重载是不可 能做到的。
如果在 ECMAScript中定义了两个名字相同的函数,则该名字只属于后定义的函数。