第4章 表达式与运算符

上一章讲解了变量和常量,本章将讲解JavaScript中另一个重要的基础内容,表达式与运算符。和其他程序语言一样,JavaScript也有自己的表达式与运算符,而且与C/C++系列语言十分相像。程序设计不外乎就是对问题进行求解,求解的过程需要进行各种各样的计算。表达式是为计算结果服务的,由操作数和运算符组成。在自然数集中,可以进行的运算有加减乘除等。对应的运算符即是“+、-、×、÷”,接下的内容将对JavaScript中的表达式与运算符一一讲解介绍。

● 理解并掌握JavaScript表达式的特点,达到灵活运用要求

● 理解并掌握各个运算符的作用和使用方法

● 结合前两章,加强练习以熟悉程序语句的编写

以上几点是对读者在学习本章内容时所提出的基本要求,也是本章希望能够达到的目的。读者在学习本章内容时可以将其作为学习的参照。

4.1 什么是表达式

表达式是产生一个结果值的式子,JavaScript中的表达式由常量、变量和运算符等组成。表达式可以作为参数传递给函数,或者将表达式结果赋予变量保存起来。表达式的结果值有多种类型,比如布尔型、字符串型或数值型等,因此常有逻辑表达式、数值表达式和布尔表达式之说。下面举例说明如何定义和使用表达式。

【范例4-1】编写程序,演示表达式的定义和使用。假设初始账户余额为1000,经过第一次支付后检测当前余额能否可以再进行第二次支付,不能则发出提示信息。如示例代码4-1所示。

示例代码4-1

        01  <script language="javascript">
        02  <!--
        03       var balance = 1000.0;                               // 余额
        04       var willPay = 300.0;                                // 应支付数额:300
        05       balance -= willPay;                                 // 当前余额
        06       document.write("当前余额为:" + balance );            // 输出余额
        07       var willPay2 = 800;                                 // 再次支付数额:800
        08       if( balance < willPay2 )                            // 当余额不足时
        09       {
        10           document.write( (",不足以进行下次支付!").fontcolor("red") );
                                                                    // 输出提示信息
        11       }
        12  -->
        13  </script>

【运行结果】打开网页文件运行程序,其结果如图4-1所示。

【代码解析】该代码段定义了几个简单的表达式。第5行使用变量balance和willPay组成算术表达式,返回当前余额。第8行的if条件语句是逻辑表达式,当balance小于willPay2时返回true值。字符串表达式返回一个字符串,布尔表达式(即逻辑表达式)返回一个布尔值,数值表达式返回一个数值。表达式可以嵌套使用,代码如下所示。

        if ( ( ( b + c ) * 30 + 70 * ( d-3 ) ) * e + 50 > 0 )   // 如果表达式的值大于0
        {
            document.write( "b+c=" + (b+c) );                   // 输出表达式的值
        }

图4-1 余额不足

提示:表达式的使用方式灵活多样,没有一定的书写规则,只需要简单易读懂,代码运行效率高即可。

4.2 什么是操作数

上一节讲到表达式时,读者已经知道其中存在一个重要的组成部分就是操作数。操作数是指表达式中的变量或常量,本书中的操作数也包含表达式的返回值(实际上就是一个常量),常提供计算用的数据。下面是操作数在表达式中的形态。

        ( A + B + C ) / D

其中,A、B、C、D就是操作数,而“+”和“/”则是操作符,操作符将在下一节介绍。操作数的数据类型受表达式的类型和运算符所支持的数据类型决定,上述代码中若表达式是数值表达式,则需要A、B、C和D的类型皆为数值或可以转换为数值。下面举例说明以加深理解。

【范例4-2】练习操作数的使用,变量和常量皆可作为操作数,如示例代码4-2所示。

示例代码4-2

        01  <script language="javascript">     // 脚本程序开始
        02  <!--
        03       var A = 1;                    // 几个简单的数值型变量,用于测试
        04       var B = 2;
        05       var C = 3;
        06       var D = 4;
        07       var E = ( A + B ) * C + D;    // 数学表达式,其中A、B、C和D为操作数
        08       document.write( E + 4 );      // 表达式 E+4 中的E和4皆称为操作数
        09  -->
        10  </script>                          <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,其结果如图4-2所示。

图4-2 表达式运算结果

【代码解析】本示例第3~6行定义数个变量作为其后表达的操作数,第8行表达式“E+4”中的4为常量,常量也可以作为操作数。

4.3 运算符概述

前面两节讲过表达式和表达式中的操作数,本节将讲解表达式的第三个重要组成部分,即运算符。运算符是指程序设计语言中有运算意义的符号,类似于普通数学里的运算符。通常,每一门数学都定义了一个数集和在数集上可以进行的运算。程序设计语言也一样,规定了其支持的数据类型及数据可以进行的运算。JavaScript的运算符包含算术运算符、逻辑运算符和一些特殊的运算符,本节将逐一介绍。

4.3.1 什么是运算符

在表达式中起运算作用的符号称运算符。在数学里,运算符就是指加减乘除等符号。在Java Script中有单目和多目之分,单目运算符带一个操作数,多目运算符带多个操作数,代码如下所示。

        ( 1 + 2 ) × 3            // 数学表达式
        ++A                       // 左结合递增

第一行中的运算符是双目运算符,第二行是单目运算符。其中,“+”也可以作正号,“-”也可以作为负号使用。在不同的场合运算符有不同的含义,依上下文情景而定。举个例子,在JavaScript中“+”运算符连接两个数值类型操作数时就作数学加运算。当其连接的两个操作数是字符串型时将作为“连接”运算,即将两个串接成一个串。JavaScript的运算符极其丰富,接下来的内容将对其进行更深入的讲解。

4.3.2 操作数的分类

表达式中的操作数要么是常量要么是变量,常量和变量都有其特定的数据类型。构成表达式的操作数的数据类型依变量或常量的类型来确定,见下面的示例。

【范例4-3】操作数的类型,如示例代码4-3所示。

示例代码4-3

        01  <script language="javascript">// 脚本程序开始
        02  <!--
        03       var a = "4";              // 字符串变量
        04       var b = 4;                // 数值型变量
        05       var c = a + b;            // 下面表达式中,操作数 b先被转换为字符串类型,
        06       alert( c );               // 即“b”再与字符串类型操作 a 进行 “+” 运算
        07  -->
        08  </script>                     <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,其结果如图4-3所示。

【代码解析】该代码段第3、4行定义两个变量,a为字符串型,b为数值型。目的是将两者进行“+”运算,以测试其结果。第5行操作数b的类型由数值型转换为字符串型。

图4-3 数字与字符连接

提示:JavaScript操作数的类型是灵活多变的,通常由运算符类型、目标场合需求的类型来定,读者编程时要多加测试。

4.4 算术运算符简介

算术运算符是定义数学运算的符号,有数学意义的运算称为算术运算。通常在数学表达式中使用,实现数值类型操作数间的数学计算。JavaScript中要包括加法、减法、乘法、除法、取模、正负号、递增和递减等。

4.4.1 加法运算符

加法运算符使用数学符号“+”,属于双目运算符,返回两个操作数的算术和。操作数的类型要求为数值型,如果是字符串型则意义不同,主要运用在数值求和的场合,其语法如下所示。

操作数1 + 操作数2

【范例4-4】编写程序,演示加法运算符,求某公司的总人数,如示例代码4-4所示。

示例代码4-4

        01  <script language="javascript">                          // 脚本程序开始
        02  <!--
        03       var departmentA = 1000;                             // 部门A 1000人
        04       var departmentB = 375;                              // 部分B 375人
        05       var total = departmentA + departmentB;              // 公司总人数
        06       document.write( "公司总人数:" + total );             // 输出人数信息
        07  -->
        08  </script>                                               <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,其结果如图4-4所示。

图4-4 总人数

【代码解析】第3、4行分别给出公司两个部门各自的人数。第5行通过使用“+”运算符进行人数求和。

提示:注意加法运算符与字串型操作数结合的情况,操作数类型为字符串型时其意义为连接运算。

4.4.2 减法运算符

减法运算符使用数学符号“-”,属于双目运算符,返回两个操作数的算术差,操作数类型要求为数值型。含义与数学上的减法计算完全一样,使用的形式如下所示。

        操作数1 - 操作数2

【范例4-5】编写程序,演示减法运算符的功能。某小汽车平均耗油量为7.5升每100公里,求其100公里行程后的剩余油量。如示例代码4-5所示。

示例代码4-5

        01  <script language="javascript">                          // 脚本程序开始
        02  <!--
        03       var totalGas = "20升";                              // 汽油总量
        04       var used = "7.5升";                                 // 开出100公里后消耗
        05       var overplus = parseFloat( totalGas ) - parseFloat( used );
                                                                    // 剩余
        06       document.write( "车子已经开了100公里,还剩汽油" + overplus + "升" );
                                                                    // 100公里时输出提示
        07  -->
        08  </script>                                               <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,其结果如图4-5所示。

图4-5 剩余油量

【代码解析】该代码段第3、4行给出汽油总量和当前消耗量。第5行使用前面讲过的parseFloat方法将字符串解析为数字,并求出汽油剩余量。

注意:JavaScript中数学运算符运用于非数字型操作数时,将发生隐式类型转换。

4.4.3 乘法运算符

乘法运算符使用符号“*”,属于双目运算符,返回两个操作数的算术积。操作数类型要求为数值型。运算意义上完全等同于数学上的乘法计算,使用语法如下所示。

操作数1 * 操作数2

【范例4-6】乘法运算符的算术意义。某公司给其属下300名员工发奖金,每人370元,求奖金预算总额。如示例代码4-6所示。

示例代码4-6

        01  <script language="javascript">                          // 脚本程序开始
        02  <!--
        03       var employee = 300;                                 // 雇员总数
        04       var prize = 370;                                    // 每人奖金数额
        05       var total = employee * prize;                       // 预算总额
        06       alert( "预算:" + total + "元" );                    // 输出总额
        07  -->
        08  </script>                                               <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,其结果如图4-6所示。

【代码解析】该代码段第5行返回变量employee和prize的积,即预算总额。“*”完全就是数学意义上的乘法符号。

图4-6 总预算

4.4.4 除法运算符

除法运算符使用符号“/”,也属于双目运算符,操作数类型要求为数值型。其返回两个操作数之商,JavaScript返回的商是实数集内的数据,也就是浮点型数据。意义上等同于数学中的除法运算,因此可用在求商的场合,使用语法如下:

        操作数1 / 操作数2

操作数1、操作数2都是数值类型,操作数2不能为0,否则将产生不正确的结果。除数为零的情况在其他编程语言中将发生一个异常,而JavaScript仅返回一个非数字(NaN)结果。

【范例4-7】除法运算符的数学含义。三个贼平均瓜分盗来的1000元钱,输出每个人所得的数额,如示例代码4-7所示。

示例代码4-7

        01  <script language="javascript">                      // 脚本程序开始
        02  <!--
        03       var total = 1000;                               // 1000元
        04       var thieves = 3;                                // 三个贼
        05       alert( "每人瓜分所得:" + total/thieves + "元" ); // 输出三人瓜分后所得数额
        06  -->
        07  </script>                                           <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,其结果如图4-7所示。

【代码解析】该代码段说明了除法运算符的数学意义,在第5行返回total除以thieves的商。

图4-7 计算结果

4.4.5 取模运算符

取模运算符使用符号“%”,其作用是求一个数除以另一个数的余数。操作数的类型要求为数值型或能转换为数值型的类型,属于双目运算符。事实上“模”可以这样理解,如手表上的小时刻度,每到12点以后就是1点,此钟表的模为12。通常取模运算可以求取某个数的倍数,如下面示例所示。

【范例4-8】求1~1000中3的倍数,如示例代码4-8所示。

示例代码4-8

        01  <script language="javascript">                  // 脚本程序开始
        02  <!--
        03       for( i = 1; i<1000; i++ )                  // 找出0到1000中3的公倍数
        04       {
        05          if( i%3 == 0 )                          // 当模3为0时即是3位数
        06          {
        07             document.write( i + " " );           // 输出
        08          }
        09       }
        10  -->
        11  </script>                                       <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,其结果如图4-8所示。

图4-8 1~1000中3的倍数

【代码解析】该代码段第3行使用for循环从1到1000中取得999个数。第5行将取得的数模3,如果为0则当前数是3的倍数。

4.4.6 负号运算符

负号运算符使用符号“-”,取负也就是等于取反。等同于数学意义上的负号,属于单目运算符,语法如下:

-操作数

【范例4-9】使用取反运算符求某个数的负值,如示例代码4-9所示。

示例代码4-9

        01  <script language="javascript">         // 脚本程序开始
        02  <!--
        03       var a = -1;                        // 负数
        04       var b = -a;                        // 取反
        05       alert( a + "取反后得:" + b );      // 输出
        06  -->
        07  </script>                              <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,其结果如图4-9所示。

图4-9 -1取反为1

【代码解析】该代码段将一个变量a的值取反后存入变量b中,再将变量b输出,两次取反等于原来的数。

4.4.7 正号运算符

正号运算符使用符号“+”,针对数值类型操作数,意义上等同于数学上的正号。属于单目运算符,语法如下:

+ 操作数

【范例4-10】学习正号运算符的特点,如示例代码4-10所示。

示例代码4-10

        01  <script language="javascript">                          // 脚本程序开始
        02  <!--
        03       var a = -1;                                         // 定义变量并赋予负值
        04       var b = +a;                                         // 定义变量并赋予正值
        05       var c = +5;                                         // 定义变量并赋予正值
        06       alert(  "a、b和c的值分别为:" + a + "、" + b + "和" + c );
                                                                    // 输出各变量的值
        07  -->
        08  </script>                                               <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,其结果如图4-10所示。

【代码解析】该代码段第4、5行对变量b、c使用“+”(正号运算符),通过第6行的输出来看,正号运算符没有任何意义。

图4-10 输出变量的值

4.4.8 递增运算符

递增运算符使用符号“++”,也称为自增运算符,属于单目运算符。可使数值类型的变量值自增一,操作数只能是变量。使用形式分左结合与右结合两种,左结合在表达式中的效果是先递增再使用,右结果则是先使用再递增。语法如下:

        变量名++;                  // 右结束递增
        ++变量名;                  // 左结合递增

【范例4-11】使用递增运算符对一个数进行递增操作,理解递增运算符的特点。如示例代码4-11所示。

示例代码4-11

        01  <script language="javascript">                      // 脚本程序开始
        02  <!--
        03       var a = 10;                                     // 数值型变量
        04       document.write( "<li>a的初始值为:" + a );       // 输出初始值
        05       if( ++a == 11 )                        // ++左结合,此时if测试条件成立
        06       {
        07          document.write( "<li>左结合,先递增再使用。" );
                                                      // 输出提示信息
        08       }
        09       if( a++ == 12 )                        // ++右结合,此时if测试条件不成立
        10       {
        11          document.write( "<li>右结合,先递增再使用。" ); // 输出提示信息
        12       }
        13       else
        14       {
        15          document.write( "<li>右结合,先使用再递增。" ); // 输出提示信息
        16       }
        17  -->
        18  </script>                                           <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,其结果如图4-11所示。

图4-11 左右结合对比

【代码解析】该代码段第5行作用于变量a的递增运算符与a结合形式为左结合,其先进行递增运算后再与11进行比较。第9行a与递增运算符结合形式为右结合,则先a先与12比较后返回一个布尔值作为if的测试条件,再进行递增操作,因此if条件为假。

提示:请区别左结合与右结合所进行的操作分别是什么,这样的疏漏很难发现。

4.4.9 递减运算符

递减运算符使用符号“--”,也称为自减运算符,可使变量的值自减一。效果与递增运算符完全相反,也有左结合与右结合之分,情况与递增运算符相同,在此不再赘述,使用形式如下:

        变量名--;                               // 右结合递减
        --变量名;                               // 左结合递减

【范例4-12】使用递减运算符对一个数进行递减操作,掌握自减运算符的特点。如示例代码4-12所示。

示例代码4-12

        01  <script language="javascript">             // 脚本程序开始
        02  <!--
        03     var a = 5;                              // 定义一个数字变量
        04     document.write( a );                    // 输出a原来的值
        05     document.write( "<br>" );               // 输出换行标签
        06     a-- ;                                   // a自减一(右结合)
        07     document.write( a );                    // 输出变量a
        08     document.write( "<br>" );               // 输出换行
        09     --a;                                    // a自减一(左结合)
        10     document.write( a );                    // 输出变量a
        11     document.write( "<br>" );               // 输出换行
        12     if( --a == 2 )                          // 测试左、右结合位于表达式中的情况
        13     {
        14         document.write( "<li>左结合的情形" );  // 输出提示信息
        15     }
        16     if( a-- == 2 )                          // 等于2时
        17     {
        18         document.write( "<li>右结合的情形" );  // 输出提示信息
        19     }
        20  -->
        21  </script>                                  // 脚本程序结束

【运行结果】打开网页文件运行程序,其结果如图4-12所示。

图4-12 左右结合对比

【代码解析】该代码段第3~10行定义一个变量并输出其进行递减操作后的值。第12行使用左结合的方式参与构成条件表达式,从输出结果表明左结合是先执行递减操作后再使用变量的值参与表达式的计算,而右结合运算顺序相反。

警告:递增递减运算符的操作数只能是变量。

4.5 关系运算符简介

关系运算符比较两个操作数大、小于或相等的运算符。返回一个布尔值,表示给定关系是否成立,操作数的类型可以任意。包括相等、等同、不等、不等同、小于、小于或等于、不小于、大于、大于或等于这几种。

4.5.1 相等运算符

相等运算符使用符号“==”,判断两个操作数是否相等。如果相等返回布尔值true,否则返回false。属于双目运算符,两个操作数的数据类型可以任意。通常与条件测试语句结合使用, JavaScript是弱类型语言,因此可以比较两种不同类型的数据。运行时,“==”操作符将两端的操作数转换为同一种数据类型后再作比较。使用语法如下:

        操作数A == 操作数B

【范例4-13】JavaScript中用“==”判断两者是否相等,理解掌握相等运算符的特点。如示例代码4-13所示。

示例代码4-13

        01  <script language="javascript">                          // 脚本程序开始
        02  <!--
        03     var a = "10";                                        // 字符串变量
        04     var b = 10;                                          // 数值型变量
        05     if ( a == b )                                        //a、b将发生类型转换
        06     {
        07         alert( "a等于b,“==”使两端的操作数发生了类型转换" );   // 输出提示信息
        08     }
        09  -->
        10  </script>                                               <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,其结果如图4-13所示。

图4-13 非严格相等

【代码解析】该代码段测试了JavaScript中“==”的功能和特点。第5行判断a与b的相等性时a和b被转换为同一种数据类型。

提示:“==”不是严格相等性判断,只要类型转换后的数据仍然相等的话就返回true。

4.5.2 等同运算符

前面讲述的相等运算符“==”进行的是非严格意义上的相等性判断,即通过类型转为后相等的也返回true。而等同运算符“===”是严格意义上的相等,两个值和它们的类型完全一致时才返回true,使用语法如下:

        操作数1 === 操作数2

两个操作数可以是变量也可以是常量,数据类型可以是任意有效的JavaScript类型,下面举例区别等同与相等运算符的作用。

【范例4-14】比较“相等运算符”和“等同运算符”的区别,如示例代码4-14所示。

示例代码4-14

        01  <script language="javascript">         // 脚本程序开始
        02  <!--
        03     var a = "10";                       // 字符串变量
        04     var b = 10;                         // 数值型变量
        05     if ( a == b )                       // a、b将发生类型转换,转换为同一种类型
        06     {
        07         document.write( "<li>在非严格意义上,a等于b" );      // 输出提示信息
        08     }
        09     if( a === b )                       // 等同运算符判断a、b的相等性
        10     {
        11         document.write( "<li>a严格等于b" );               // 输出提示信息
        12     }
        13     else                                                 // 都不相等时
        14     {
        15         document.write( "<li>在严格意义上,a不等于b" );      // 提示
        16     }
        17  -->
        18  </script>                                               <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,其结果如图4-14所示。

【代码解析】该代码段对两个不同类型的变量进行相等性判断。第5行进行的是非严格相等性判断,条件表达式返回true。第9行进行的是严格相等性判断,因a、b的类型不同,表达式返回false。

4.5.3 不等运算符

不相等运算符使用符号“!=”,属于双目运算符,返回一个布尔值表示两个操作数是否相等。两个操作数类型任意,同时可以是变量也可以是常量。使用语法如下:

        操作数1 != 操作数2

图4-14 对比严格与非严格相等

不等运算两端的操作数如果经过类型转换后仍不相等的话同样返回true,否则返回false。不是严格意义上的不相等。

【范例4-15】在几个学生当中找出名为“杨宗楠”的学生,并用红色字体标记之,如示例代码4-15所示。

示例代码4-15

        01  <script language="javascript">                               // 脚本程序开始
        02  <!--
        03       var students = new Array( "杨宗楠", "杨玉婷", "李莉" );    // 学生名单
        04       for( index in students )                                // 遍历名单
        05       {
        06          if( students[index] != "杨宗楠" )        //不是“杨宗楠”则输出为黑色字体
        07          {
        08             document.write( "<li>" + students[index] )        // 普通输出
        09          }
        10          else                                    // 否则
        11          {
        12             document.write("<li><font color=red>"+students[index]"</font>");
                                                          // 红字输出
        13          }
        14       }
        15  -->
        16  </script>                                       <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,其结果如图4-15所示。

图4-15 标记目标名字

【代码解析】该代码段第3行创建一个数组students以记录学生的名字,共有三个学生。第4~14行遍历学生表,并输出各学生名字,对目标名字以红色字输出。第6行使用了不等于运算符“!=”判断两个名字是否相等。

4.5.4 不等同运算符

不等同运算符使用符号“!==”,属于双目运算符。效果与等同运算符正好相反,如果两个数严格不相等则返回true,使用语法如下:

        操作数1 !== 操作数2

运算符两端的操作数可以是变量或常量,变量或常量的数据类型任意。不等同于运算符使用场合并不多,用法如下所示。

        01  var phone1 = "13800000000";                     // 定义字符串型的电话号码
        02  var phone2 = 13800000000;                       // 定义数值型电话号
        03  if( phone1 !== phone2 )                         // 严格不相等判断,此时返回true
        04  {
        05       alert( "两个电话号码不相等" );                // 提示
        06  }

前面讲过相等、不相等,等同、不等同4个运算符,前两者是非严格意义上的等与不等,后两者是严格意义上的等与不等,读者要注意这其中的区别。

4.5.5 小于运算符

小于运算符是判断第一个操作数是否小于第二个操作数的运算符,返回一个布尔值。使用符号“<”表示,常用于逻辑表达式中。使用语法如下:

        操作数1 < 操作数2

如果操作数1小于操作数2时则表达式返回true,否则返回false。两个操作数可以是变量也可以是常量,变量或常量可以是任意有效的JavaScript数据类型。小于运算符应用广泛,比如可以用于筛选出目标数据,如下面示例所示。

【范例4-16】现有一网络游戏点卡销售系统的购买页面,要求输入的点卡数量不小于1,需要在用户确定付账时检测其输入的数据是否符合要求,如示例代码4-16所示。

示例代码4-16

        01  <body>                        <!--文档体开始-->
        02                                 <!--配置一个文件输入框和一个按钮,与用户交互用-->
        03  <li>50点点卡单价为4.5元,您确定购买 <!--价格信息-->
        04  <input id="Text1" style="width: 31px; height: 18px" type="text" />张。
                                          <!--文本框-->
        05  <input id="Button1" type="button" value="确定支付" onclick="return Button1_
            onclick()" />  <!--按钮 -->
        06  (最多不能超过5张)
        07  <script language="javascript">                      // 脚本程序
        08  <!--
        09  function Button1_onclick()                          // 按钮单击事件处理程序
        10  {
        11     if( (Text1.value < 1) || isNaN(Text1.value) )
                                          // 输入小于0或不是数字,则清除文本框内容并要求重输
        12     {
        13         alert( "您的输入不正确,请重新输入" );            // 警告
        14         Text1.value = "";                             // 清空输入框
        15     }
        16     else                                             // 输入合法则统计总金额
        17     {
        18         alert( "您的应当支付:" + Text1.value * 4.5 + "元" );
                                                                // 输出应该支付的金额
        19     }
        20  }
        21  -->
        22  </script>                                           <!--脚本程序结束-->
        23  </body>                                             <!--文档体开始-->

【运行结果】打开网页文件运行程序,其结果如图4-16所示。

图4-16 操作效果

【代码解析】该代码段实现一个简单的账单验证功能。第3~6行用一个文本框和一个按钮实现用户界面,并在按钮上绑定按钮单击事件处理程序。第9~20行定义一个函数作为按钮单击事件处理函数。其中第11行用小于运算符检测输入的点卡数量是否少于1张,或者输入的是非数字,如果这两条件至少有一个成立则要求重新输入。第18行在用户输入点卡数量正确的情况下输出统计金额。

注意:使用运算符时请注意操作数的类型。

4.5.6 大于运算符

大于运算符与小于运算符的运算效果正好相反,使用符号“>”,主要用于测试两个操作数的大小关系。使用语法如下:

        操作数1 > 操作数2

操作数可以是变量或常量且数据类型是任意有效的JavaScript类型。当第一个操作数大于第二个操作数时表达式返回true,否则返回false,下面举例加深读者理解。

【范例4-17】现有一个购物网站的支付确认页面,提供结算用户账单信息的功能。如果当前余额不足以进行本次支付则取消操作,否则输出结算信息。如示例代码4-7所示。

示例代码4-17

        01  <body style="font-size: 12px">         <!--页面普通字体大小为12px-->
        02  <script language="javascript">
        03  <!--
        04     var actTotal = 109.7;               // 账单总额
        05     var payTotal = 123.45;              // 当前应该付的款额
        06     document.write( "<li>您账上余额:" + actTotal + "元<br>" );
                                                  // 输出账面信息
        07     document.write( "<li>您需要支付:" + payTotal + "元<br>" );
        08     document.write( "<input id=\"BtnPay\" type=\"button\" value=\"确认支付\"
                onclick="
        09           + "\"return BtnPay_onclick()\" style=\"width: 150px\" /><br>" );
                                          // 生成“确认支付”按钮
        10     if( payTotal > actTotal )  // 如果余额不足,支付按钮设置为失效
        11     {
        12        document.write( "信息:<fontcolor=red>您的余额不足,无法完成支付!</font>");
        13         BtnPay.disabled = true;
        14     }
        15     else                       // 余额够用于支付,则启用按钮
        16     {
        17         BtnPay.disabled = false;
        18     }
        19     function BtnPay_onclick()  // 按钮单击事件处理函数,主要处理表达发送输出结算信息
        20     {
        21         // Todo:                // 在此添加发送数据到服务器的操作代码
        22         document.write( "<li><font color=red>已经完成支付</font>" );
        23         document.write( "您账上余额:" + (actTotal-payTotal) + "元<br>" );
        24     }
        25  -->
        26  </script>
        27  </body>

【运行结果】打开网页文件运行程序,其结果如图4-17所示。

图4-17 支付前检查余额

【代码解析】该代码段实现了支付页面简单的功能,主要验证用户的余额是否足以进行交易。第1行设置本页普通字体的尺寸。第4、5行手工设定账户余额和该付数额。第8行生成一个按钮,主要用于确认支付操作。第10~14行对余额进行判断,如果够用则启用“确认支付”按钮。否则该按钮变灰,无法使用,使得余额不足时不能进行交易。

4.5.7 小于或等于运算符

小于或等于运算符判断第一个操作数和第二个操作数间是否是小于等于关系,使用符号“<=”。当第一个操作数小于或等于第二个操作数时表达式返回true,否则返回false。使用语法如下:

        操作数1<=操作数2

两个操作数可以是变量或常量,数据类型可以是任意有效的JavaScript类型。通常用于取大小关系的场合,示例如下:

        01  var a = 5;                                          // 数值变量a
        02  var b = 5;                                          // 数值变量b
        03  if( a <= b )                                        // 如果a等于小于b则
        04  {
        05       // todo                                         // 执行语句
        06  }

以上条件表达式返回true,因为有a=b。只要a=b或a<b即可返回true。相反的情况是当a>b时返回false。

注意:字符串也可以比较大小。

4.5.8 大于或等于运算符

大于等于运算符与小于等于运算符有部分不同的地方,其判断第一、第二个操作数间的关系是否是大于等于关系。满足此关系则表达式返回true否则返回false。操作数的类型要求与小于等于运算符相同,使用“>=”表示。使用语法如下:

        操作数1 >= 操作数2

该运算符通常应用于求大小关系的场合。例如当用户输入其年龄为1000,这是不太可能的,因此可以将年龄数据视为不符合要求,如下述代码所示。

        01  var age = 1000;                            // 年龄
        02  if( age >= 100 )                           // 大于等于100时
        03  {
        04       age = 0;                               // 更正为0
        05  }

age在此处等于1000,因此条件表达式返回true,执行流程进入if语句块中。大于等于运算符只需要满足第一个操作数大于或等于第二个操作数表达式即可返回true。

4.5.9 in运算符

前面介绍过的运算符都与其在数学上的意义相同或相似,但JavaScript毕竟不是数学,因此也有很多独特的运算符。in运算符就是其中之一,in运算符检查对象中是否有某特定的属性。通常,在数组对象中存在一种称为元素索引的属性集合,该集合的每个元素都是一个非负整型值。因此可以通过in运算符取得数组索引集合,这是个非常有用的运算符。语法如下:

        result = property in Object;

property为Object对象包含的属性集合,result接收从集合中按顺序逐一提取的属性。in运算符应用十分广泛,通常用于遍历集合中的所有元素,比如数组,下面举例说明以加深印象。

【范例4-18】有5种水果的价格数据,分别是梨3.5元、葡萄7元、香蕉2元、苹果3元和荔枝6元。现需要将这5种水果的价格显示在网页的价目表上以供客户查询,如示例代码4-18所示。

示例代码4-18

        01  <body>
        02  <script language="javascript">             // 脚本程序开始
        03  <!--
        04     var fruit = new Array( "梨", "3.5", "葡萄", "7", "香蕉", "2",  "苹果", 3, "
              荔枝", 6 );                               // 水果数组
        05     for ( index in fruit )                   // 使用in运算符遍历水果数组
        06     {
        07         if( index%2 == 0 )                   // 如果索引为偶数即为水果名
        08         {
        09            document.write( "<li>" + fruit[index] + ":");
        10         }
        11         else                                 // 元素索引为奇数则为对应水果的价格
        12         {
        13             document.write( fruit[index] + "元\t" );
                                                      // 输出水果价格
        14             document.write( "<input id=\"Button"+ index + "\" type=\"button\" "
                                                      // 生成购买按钮
        15             +"value=\"购买\""+"onclick=\"return Button1_onclick(this.serial
                      -1)\" serial=\""
        16             + index +"\" /><br>" );         // 输出
        17         }
        18     }
        19    function Button1_onclick( arg )           // 购买按钮的单击事件处理漋数
        20    {
        21        alert("您即将购买:" + fruit[arg] );    // 根据按钮序列号判断客户购买的水果
        22    }
        23  -->
        24  </script>
        25  </body>

【运行结果】打开网页文件运行程序,其结果如图4-18所示。

图4-18 商品列表

【代码解析】该代码段实现了水果价格发布功能,每种水果都生成与其对应的一个购买按钮。第4行使用一个数组来保存水果的名称和其价格,偶数元素保存水果名,奇数元素保存价格。第7~10行输出偶数元素,成为一行信息的第一部分。

第11~18行输出价格(奇数元素)作为对应信息行的第二部分,同时生成一个“购买按钮”。购买按钮的单击事件处理程序绑定到第19~22行定义的函数,处理用户单击“购买”按钮的事件。

提示:本例综合了前面所学的知识,也用到了后面才讲到的知识,读者现在不必深究,重点在于理解in运算符。

4.5.10 instanceof运算符

instanceof运算符返回一个布尔值,表明某对象是否是某个类的实例。得到一个对象时,有时需要得知其属于哪个类,确定对象的身份。使用语法如下:

        result = Obj instanceof Class

如果Obj是类Class的对象,刚result值为true否则为false。通常使用在布尔表达式中,以确定对象的类型,比如有一个数组对象,可以使用instanceof运算符来确定该对象是否是数组类型。如下面代码所示。

        var nameList = new Array( "Lily", "Bob", "Petter" );         // 创建一个名字数组
        var nameJet = "Jet";                       // Jet的名字
        if( nameList instanceof Array )            // 如果nameList是属性数组对象的实例,则
        {
            nameList.push(nameJet );               // 将Jet的名字添加到数组中
        }
        if( nameJet instanceof Array )             // 检查nameJet是否是数组对象的实例
        {
                                                  // 一些有效的程序语句
        }

以上代码段中if语句测试表达的值返回true,因为nameList正是Array类的对象。然而nameJet则不是Array类的对象,因此第二个if语句的测试条件为false。第二对花括号中的语句不会被执行。

提示:使用instanceof可以判断某一对象是否是某一个类的实例,当要确定某个对象的类型时可以使用typeof运算符。

4.6 字符串运算符简介

前面讲过了常见的数学运算符、关系运算符和一些特殊的运算符,本节将介绍与字符串相关的运算符。字符串也是一种数据,同样也存在相应的计算,因此程序设计语言也为字符串定义了相应的运算符。主要包括+、>、<、>=和<=这几种。接下来逐一介绍每个运算符的功能。

运算符“+”,称为连接运算符,它的作用是将两个字符串按顺序连接成为新的字符串。这大大简化了字符串表达式的写法,使用语法如下:

        result = string1 + string2;                // 连接字符串

string1和string2可以是字符串变量或常量,连接后形成的新串存入变量result中。也可以将连接后的新串作为参数传递,代码如下所示。

        var str1 = "今天星期几了?";                  // 字符串变量
        var str2 = "星期五";                        // 字符串变量
        document.write( str1 + str2 );             // 输出连接后的字符串

上述代码中将str1和str2用连接运算符连接为一个串后作为参数传递给write方法。document对象的write方法要求一个字符串作为参数。

4.7 赋值运算符简介

赋值运算符“=”,用于给变量赋值。赋值运算符将值与变量绑定起来,也就是说,值写入了变量所引用的内存单元。通常,仅声明的变量是没有初始值的,给变量填入数据最直接的办法就是使用赋值运算符将值赋予变量。代码如下所示。

        var name = "Jet";                      // 字符串

以上代码将“Jet”赋予变量name,“=”运算符左边的操作数称为左值,其右边的操作数称为右值。左值必须是变量,右值可以是变量、常量或表达式。读者要注意区分以下两个概念。

● 声明,指仅宣布变量的存在,但没有为其实际分配存储空间。代码如下所示。

        var name;                              // 声明变量

变量name仅声明,表示它的存在,系统并不为它分配存储空间。

● 定义,声明并赋值。系统真正为变量分配存储空间,代码如下所示。

        var name = "Lily";                     // 定义字符串变量

4.8 逻辑运算符简介

除了数学运算外,程序设计语言还包含另一种重要的运算,逻辑运算。通常是与、或、非和移位等,JavaScript也为此类运算定义了相应的运算符。包括逻辑与、逻辑或和逻辑非等,本节将逐一讲解。

4.8.1 逻辑与运算符

逻辑与运算符“&&”,属于双目运算符,操作数被当成布尔类型,可以是变量也可以是常量。“&&”运算符的使用语法如下:

        操作数1 && 操作数2                      // 与运算

将第一个操作数和第二个操作数相与,返回一个布尔值。在日常生活中,常遇到这样的情形,达到两厢情愿需要两个条件,A喜欢B,B也喜欢A。其中少一个都不行。为了判断A和B是否达到了两厢情愿,只需要将A和B这两条件作相与运算即可。代码如下所示。

        01  var AWish = true;                  // A同意
        02  var BWish = true;                  // B同意
        03  if( AWish && BWish )               // 逻辑表达式
        04  {
        05                                     // 达到两厢情愿
        06  }

逻辑与运算符通常用于判断多个条件同时成立的场合,多个条件相与时需要所有条件都成立表达式才返回true,下面举例以加深理解。

【范例4-19】现有一付费影片下载网站的某个页面,其上某个影片对下载用户有要求:必须是2级注册用户,并且下载点数至少30点余额。不满足条件的用户不予以下载,限制功能的实现如示例代码4-19所示。

示例代码4-19

        01  <body>                             <!--文档体开始-->
        02  <script language="javascript">     // 脚本程序开始
        03  <!--
        04  function Button1_onclick()         // 按钮事件处理程序
        05  {
        06     var isRegistered = true;        // 注册用户
        07     var level = 3;                  // 级数为3
        08     var blance = 25;                // 账户余额
        09     if( isRegistered && ( level >= 2 ) && ( blance >= 30 ) )
                                              // 必须是注册用户、等级大于等于2、余额大于30
        10     {
        11         alert( "您可以下载本资源" );   // 当前用户条件都满足时
        12     }
        13     else
        14     {
        15         alert( "您不能下载本资源" );   // 至少有一个条件不满足时
        16     }
        17  }
        18  -->
        19  </script>                          <!--脚本程序结束-->
        20     单击下载本影片
        21     <input id="Button1" type="button" value="下载" onclick="return Button1_
            onclick()" /> <!--下载按钮-->
        22  </body>

【运行结果】打开网页文件运行程序,结果如图4-19所示。

图4-19 下载前检测

【代码解析】该代码段实现了影片下载前检测用户状态的功能。第21行设置一个下载按钮,用户单击它即可启动下载。第4~17行定义一个函数作为下载按钮的单击事件处理程序,此程序检测用户的状态。第9行用与运算符检测三个条件,“是否已经注册”、“是否达到至少2级”和“是否至少有30点的余额”这三个条件,只要至少一个条件不成立,表达式即返回false。从而不能进入下载页面,条件都成立则可以下载。

提示:逻辑运算符也可以用于非逻辑表达式中。

4.8.2 逻辑或运算符

逻辑或运算符“||”,属于双目运算符,对两个操作数进行或运算并返回一个布尔值。返回值表明两个操作数中是否至少有一个的值为true,操作数可以是常量或变量,类型皆被转换为布尔型。使用语法如下:

        操作数1 || 操作数2

逻辑或运算符通常用于判断多个条件中至少有一条成立即可通过测试的场合。例如某个人仅凭身份证或学生证即可领取邮局里的邮包,可使用逻辑或运算符,代码如下所示。

        01  var identity_card = true;                       // 身份证
        02  var student_IDC = false;                        // 学生证
        03  if( identity_card || student_IDC )              // 是否带两了至少一种证件
        04  {
        05                                                  // 允许领取
        06  }
        07  else                                            // 否则
        08  {
        09                                                  // 不允许领取
        10  }

上述代码中只需要identity_card或student_IDC为true,if语句的测试条件为真,则允许领取邮包,否则不允许。

4.8.3 逻辑非运算符

逻辑非运算符“!”,属于单目运算符。对操作数的逻辑值取反,操作数可以是变量或常量。类型可以是任意JavaScript数据类型,和逻辑非运算符结合后的数据类型皆被当做布尔型。如果原来的值为true运算后将为false,反之为true。语法如下:

        var v = false;                                  // 布尔型变量

逻辑非运算符通常用于测试当某条件不成立时(即为false),再通过一次取反条件则成立。条件语句测试通过,以原条件不成立为执行前提的代码就得到执行,代码如下所示。

        01  var isBob = false;
        02  if( !isBob )                               // 如果不是Bob时
        03  {
        04                                              // 如果此用户不是Bob时而采取的行动
        05  }

4.9 位运算符简介

前面所讲的逻辑与、逻辑或和逻辑非都是依据操作数的值转换为布尔值后参与计算。例如非零值为true,零值为false。而位运算符则对变量的二进制位间进行逻辑运算,因而取得一个新的值。位级运算符包括位与、位或、位异或、位非和移位运算符。

学习位运算符之前,应该先了解存储单元的位模型。通常计算机中每一个内存单元是一个字节,一个字节由8个二进制位组成,二进制位是计算机里的最小的信息单元,模型如图4-20所示。

图4-20 内存单元位模型

图4-20中黑粗边框表示一个内存字节单元,由8个二进制位构成。该单元的二进制值为01000110,是无符号数字74。位运算符对变量进行的运算是发生在二进制位级别,因此返回的值通常不用做布尔值。

4.9.1 位与运算符

位与运算使用符号“&”,属于双目运算符。两个操作数的对应二进制位相与,对应两个位都为1时结果值中对应位也为1,否则为0。结果值的长度和两个操作数中位数最多者相同,通常用于测试某个操作数中的某位是否为1,作为开关使用。语法如下:

        var result = 操作数1 & 操作数2;

【范例4-20】某地下通道有8条行车线,每5分钟只能随机允许其中数条通车。用红绿灯控制车道的停通,1表示绿灯,0表示红灯。测试1、3、5、7车道是否开通的程序如示例代码4-20所示。

示例代码4-20

        01  <body>                                          <!--文档体开始-->
        02  <script language="javascript">                  // 脚本程序开始
        03  <!--
        04  function Button1_onclick()                      // 按钮单击事件处理程序
        05  {
        06     var currentState = 215;                      // 目前车道开放的状态
        07     if ( (currentState & 85) == 85 )             // 测试第1、3、5、7位是否为1
        08     {
        09         alert( "已经开通1、3、5、7车道" );          // 输出信息
        10     }
        11     else                                         // 其中至少有一位不为1
        12     {
        13         alert( "1、3、5、7车道目前处于关闭状态" );   // 输出信息
        14     }
        15  }
        16  -->
        17  </script>                                       <!--脚本程序结束-->
        18                                                  <!-检查按钮-->
        19     <input id="Button1" type="button" value="查看1、3、5、7道是否已经通车"
        20   onclick="return Button1_onclick()" />
        21  </body>                                         <!--文档体结束-->

【运行结果】打开网页文件运行程序,结果如图4-21所示。

图4-21 程序运行效果

【代码解析】该代码段使用位与运算符检测一个字节单元中的第1、3、5、7位是否为1,将该单元的值与85做位与运算即可实现。第6行定义一个变量表示当前地下车道开放的状态, 215的二进制码为11010111。表示第1、2、3、5、7、8道开通。第7行将状态码215与85做位与运算,85的二进制码为01010101,表示第1、3、5、7道开通。位与操作后如果结果为85则表示目标通道开通,否则至少有一条目标通道是关闭的。

4.9.2 位或运算符

位或运算符“|”原理与位与运算符基本上一样,唯一的差别就是两个操作数对应位间如果都不为0则结果的相应位为1,否则为0。使用的情形不再重述,语法如下:

        var result = 操作数1 | 操作数2;

例如2的二进制码为10,3的二进制码为11。2和3作位或运算则得3,因为2的第一位和3的第一位至少有一个为1。因此结果的第一位为1,2的第2位和3的第2位至少有一个为1,则结果的第2位也为1。因此计算结果为3,即二进制码11。

提示:注意结合位与运算符的特点,这两者正好互补。

4.9.3 位异或运算符

位异或运算符“^”的作用是当两个操作数对应位不相同时结果的相应位即为1,否则为0。应用的情形与位与、位或相同,仅仅存在功能上的区别。人们通常使用该运算符测试两个位是否相同,语法如下:

        var result = 操作数1 ^ 操作数2;

例如,2与的二进制码为10,1的二进制码为01。2与1作位异或运算将得到3,因为两者的第一二位正好不相同,因此得到二进制码11,也就是十进行数字3。通常,位异或用在信息加密解密的场合,因为A和B位异或运算得C,C和B位异或运算得A。

【范例4-21】妙用位异或运算实现信息加密解密。为了不使密码“123456”以明文的形式存放,现将其加密,密钥为“666666”,输出加密后和解密后的密码。如示例代码4-21所示。

示例代码4-21

        01  <script language="javascript">                      // 脚本程序开始
        02  <!--
        03     var user = "foxun";                              // 用户名
        04     var password = 123456;                           // 密码,需要对其加密
        05     var key = 666666;                                // 加密密钥
        06     var codedpassword = password ^ key;              // 将明文密码123456加密
        07     alert( "加密后的密码:" + codedpassword );         // 输出加密后的密
        08     codedpassword ^= key;                            // 将加密后的密码解密
        09     alert( "解密后的密码:" + codedpassword );         // 输出解密后的密码
        10  -->
        11  </script>                                           <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,结果如图4-22、图4-23所示。

图4-22 加密后密码

图4-23 解密后密码

【代码解析】该代码段第3~5行设定了用户信息,包括用户名、密码和加密密钥。第6行将密码和密钥进行位异或运算,得到加密后的密码。第7行输出加密后的密码,以表示加密成功。第8行将加密后的密码与密钥进行位异或运算,实现解密。第9行将解密后的密码输出,表示解密成功。

4.9.4 位非运算符

位非运算符“~”实现对操作数按位取反运算,属于单目运算符。操作数可以是任意JavaScript类型的常量或变量。运算的过程和结果如图4-24所示。

图4-24 位非运算符示意图

使用语法如下:

        result = ~操作数;

通过大量的实验证明,JavaScript中对数据的位非运算有其独特的规律。看起来并不完全等同于其他编程语言所进行的位级运算,对于字符串数据,按位取反后值为-1。对布尔值true和false取反分别得-2和-1,对数值数据+N得-(N+1),-N得N-1。下面编写程序逐一测试。

【范例4-22】测试按位反运算符,寻找其计算规律,如示例代码4-22所示。

示例代码4-22

        01  <script language="javascript">         // 脚本程序开始
        02  <!--
        03     var msg = "正数取反:";
        04     for( i = 0; i<50; i++ )    // 连续对0到49进行位取反,并逐一添加输出字符串
        05     {
        06         msg += i + "=>" + (~i) + " ";    // 添加取反后的值到字符串中
        07     }
        08     msg += "\n负数取反:";
        09     for( i = -50; i<0; i++ )   // 连续对-50到-1进行位取反,并逐一添加到输出字符串
        10     {
        11         msg += i + "=>" + (~i) + " ";    // 添加取反后的值到字符串中
        12     }
        13     msg += "\n布尔值取反:";
        14     var b1 = true;             //对布尔值true和false按位取反,并添加到输出字符串
        15     msg += b1 + "=>" + (~b1) + " ";     // 添加取反后的值到字符串中
        16     var b2 = false;
        17     msg += b2 + "=>" + (~b2) + " ";     // 添加取反后的值到字符串中
        18     msg += "\n字符串取反:";
        19     var name = "Bob";                   // 对布尔值字符串按位取反,并添加到输出字符串
        20     msg += "\"" + name + "\"" + "=>" + (~name) + " ";
        21     alert( msg );                       // 输出
        22  -->
        23  </script>                              <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,结果如图4-25所示。

图4-25 各种数据的位反结果

【代码解析】该代码段第3~12行对数值数据的正负数分别按位取反,以寻找其中规律。第14~17行对布尔值进行位取反,通过输出结果发现布尔值数据在取反前事先转换为数值型。第19行对字符串对象按位取位,得到“-1”,说明对象按位取反皆为“-1”,对象特性值则不然。

4.9.5 左移运算符

内存单元中的二进制数据按位作前述的与、或、反的运算可以形成新的数据。通过整体向左向右移动也可以形成新的数据。左移位运算符“<<”,实现整体向左移动低位补0的功能,属于双目运算符,语法如下:

        result = 操作数1 << 操作数2

操作数1向左移动用操作数2表示的位数,例如“50<<3”可以将数据1的二进制位序列整体向左移动3位,代码如下所示。

        var bitSet = 50;
        bitSet = bitSet<<3;

50的二进制码110010向左移3位后为110010000,等于十进制数400。向左移n位相当于原数乘以2n,执行的过程如图4-26所示。

图4-26 左移位示意图

提示:移位时一定考虑因为符号位的移动而带来的影响。

4.9.6 带符号右移运算符

前面讲过左移位运算符,与之对应的是右移位运算符。右移位包括带符号位右移和无符号位右移,共同之处是都移动给定的位数,不同之处是高位的处理方式不同。进一步学习移位操作之前,先来了解计算机中表示有符号数的方法。

通常,数据存储于计算机内存单元中。对于有符号数,除了保存表示数据大小的二进制位外,还使用一位来表示数据的符号。一般在最高位使用“1”表示负数,“0”表示正数。例如“-10”的二进制码为11100,“+10”的二进制码为01100。最左边那位就是符号位,当进行右移位运算时将面临符号位如何处理的问题。

当移动的是有符号数,左边空出的位用数的符号位填充。向右移动超出的位将被丢弃,称为带符号右移位操作。其运算符为“>>”,使用语法如下:

        result = 操作数1>>操作数2;

两个操作数可以是任意JavaScript类型的变量或常量,操作数1的二进制位向右移用操作数2表示的位数。代码如下所示。

        var number = -5;
        number = number>>2;

有符号数-5的二进制码为1101,右移2位后变为11;再使用符号位对左边空出的两位进行填充,因此最后变为1111。

提示:进行移位运算后数据的值将被更新,在位级控制应用中的意义更大,在类似JavaScript这种自动化脚本语言中并不常用。

4.9.7 高位补0右移运算符

前面已经提及右移运算时符号位的处理问题,那是针对有符号数的情况。当数是无符号数时,右移后在左边空出的位上填充0,称为无符号右移位。对应的运算符是“>>>”,使用语法如下:

        result = 操作数1>>>操作数2;

操作数可以是任意类型的变量或常量,操作数1的二进制码将被右移用操作数2表示的位数,左边空出的位用0填充。右边超出的位被丢弃,例如无符号数5的二进制码为101,向右移2位后为001,也就是十进制数1。运算过程与有符号差不多一样,读者学习时将二者联系起来。

4.10 其他运算符

前面讲过操作数、算术运算符和逻辑运算符等,这些是程序设计语言最基本的要素。但是程序设计语言不是纯粹的数学计算和逻辑推理。因此程序设计语言还需要配备一些特殊的运算符用在一些特殊的场合。本节将介绍条件运算符、new运算符、void运算符、typeof运算符、点运算符、数组存取运算符、delete运算符、逗号运算符、this运算符等。这些运算符相当重要,希望读者熟练掌握。

4.10.1 条件运算符

编程经常遇到根据条件在两个语句中执行其一的情况,用一个if语句显得麻烦。为简化程序的编码JavaScript提供了条件运算符,可以根据条件在两个语句间选择一个来执行。使用符号“?:”,属于三目运算符,语法如下:

条件表达式 ? 语句1:语句2

参数说明:

● 条件表达式,结果被作为布尔值处理的表达式。

● 语句1,如果条件表达式返回true则执行之。

● 语句2,如果条件表达式返回false则执行之。

条件运算符通常用于组织复杂的表达式。代码如下所示。

        var hours = 8;                // 已经8点
        var msg = "现在是" + ( ((time<=12)&&(time>=6)) ? "上午":"不是上午" );

上述字符串表达式中使用了条件运算符,其判断当前时间而确定将哪个字符参与字符串连接运算。使用条件运算符大大方便了代码的编写。

提示:尽管条件运算符在一些场合表现得很好,但也不能滥用。为了代码有更好的可读性,表达式不宜过于复杂。

4.10.2 new运算符

JavaScript是基于对象的语言,本书第2章在讲解有关复合数据类型的内容时已经创建了大量的对象。创建对象的一种方式是直接使用new运算符,该运算符创建一个类的实例对象。语法如下:

        new constructure( [args,[…]] );

参数说明:

● constructure:是类的构造函数,用于构造对象。

● args:是传递给构造函数的参数,可选项。

例如,创建一个字符串对象的代码如下:

        var myName = new String( "Foxsir" );

变量myName引用了新建的String对象,常量“Foxsir”被作为参数传递给String类的构造函数String( arg )。使用new运算符创建的对象,若要删除须对引用对象的变量赋null值。

4.10.3 void运算符

前面讲过的表达式都可以返回一个值,然而有些地方却不需要返回值。此时可以使用void运算符来避免表达式返回值,void运算符可以带来灵活的设计。例如将JavaScript代码写到IE地址栏中并执行,为了使当前文档内容不至于被清除,地址栏中的代码不能有返回值。

【范例4-23】使用IE地址栏来执行简单的JavaScript代码,使之打开微软公司的网站首页(http://www.microsoft.com)。如示例代码4-23所示。

示例代码4-23

        01  javascript:void( window.open("http://www.microsoft.com") );
                                                                // 在浏览器地址栏中执行

【运行结果】打开网页文件运行程序,结果如图4-27所示。

图4-27 在地址栏中执行JavaScript代码

【代码解析】程序仅有一行代码,而且写到IE地址栏中。windows对象的open方法可以打开一个新窗口,并加载指定地址的文件。open方法返回一个值引用新打开的窗口,如果不使用void运算符屏蔽返回值,当前窗口的内容将被清除并且写入“[Object]”。

提示:void可以让表达式被执行而结果被忽略,这个特性在一些场合非常有用。

4.10.4 类型检测运算符

因为JavaScript中每一个数据都属于一种数据类型,通过使用typeof运算符即可获得数据的类型名。typeof返回一个表达式的值的类型名,在一些需要得知对象的类型的场合非常有用。使用语法如下:

        typeof( 表达式 );

typeof返回6种可能的值,分别为“Number”、“String”、“Boolean”、“Object”、“Function”和“undefined”。例如求一个字符串对象的类型,代码如下所示。

        var message = "欢迎您访问本站";                   // 消息字符串
        var type = typeof(message );                    // 取变量类型名

4.10.5 对象属性存取运算符

对象属性存取运算符在一些书籍中称为点号运算符,使用符号“.”表示。其作用是读取对象的属性,或者保存值到对象的属性,或者调用对象的方法。使用语法如下:

        对象名.属性名或方法名
        类名.方法名

第一种是调用实例对象的属性或方法。对象名必须是有效的对象引用,属性名或方法必须是对象所拥有的特性。第二种是调用类的静态方法,静态方法是所有对象共有的,类无须实例化即可使用的方法。例如为了求“杨宗楠”的名字长度,可以使用如下代码。

        01  var nameYZN = "杨宗楠";                         // 创建一个字符串对象
        02  var len = nameYZN.length;                      // 调用String类对象的length属性
        03  var xing = nameYZN.charAt(0); // 调用String类对象的charAt方法,取得宗楠的姓
        04  var unicodeOfYang=String.fromCharCode(26472);// “杨”的unicode编码为26472

上述代码演示了如何使用点号运算符调用对象的属性和方法,以及如何调用类的静态方法。第4行直接调用String类的静态方法fromCharCode,将unicode码26472转为“杨”字。

4.10.6 数组存取运算符

数组以元素为单位保存数据,读取其中的数据时需要读出元素。JavaScript提供“[]”运算符用于存取数组元素,方括号中是要存取的元素的下标。这个运算符大大方便了数组的编程,使用语法如下:

        数组名[下标]

通常使用一个循环将下标从0递增到数组的最大下标,结合“[]”运算符即可遍历数组,下面举例以加深印象。

【范例4-24】现在5个学生名字,存于数组中。要求将5个名字按存放的顺序输出,如示例代码4-24所示。

示例代码4-24

        01  <script language="javascript">             // 脚本开始
        02  <!--
        03       var nameList=new Array("Tom","Lisley","Petter","ZongNanYang","Lily",
                "Jackson" );                           // 名单
        04       for( index in nameList )               // 遍历名单
        05       {
        06           document.write( nameList[index] + "<br>" );
                                                      //使用“[]”运算符读取数组元素的内容
        07       }
        08  -->
        9   </script>                                  <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,结果如图4-28所示。

图4-28 输出名字

【代码解析】该代码段第3行创建一个数组用于保存学生的名字,第6行在循环语句中使用“[]”逐一提取数组元素。

4.10.7 delete运算符

要删除使用new运算符创建的对象需要将对象的引用赋值null,当引用为0时系统自动收回对象所占的资源。delete运算符则可以删除对象的一个属性或数组的一个元素,JavaScript对象的属性可以动态添加。对于动态添加的属性可以用delete运算符将其删除,与其他面向对象的编程语言不同。

【范例4-25】用一个对象表示一个学生,为其动态添加姓名、性别和年龄等属性。如示例代码4-25所示。

示例代码4-25

        01  <script language="javascript">                  // 脚本程序开始
        02  <!--
        03    var student = new Object();                   // 创建一个对象表示学生
        04    student.name = "Tom";                         // 为学生对象添加“名字”属性
        05    student.age = 20;                             // 添加“年龄”属性
        06    student.sex = "男";                           // 添加“性别”属性
        07                                                  // 输出学生的三个属性
        08    document.write( "<li>" + student["name"] + ":" + student["sex"] + " " +
              student["age"] );
        09    delete student.age;                           // 删除学生的“年龄”属性
        10                                                  // 再次输出全部属性作对比
        11    document.write( "<br>删除了age属性<br><li>" + student["name"] + ":"
        12  + student["sex"] + " " + student["age"] );
        13  -->
        14  </script>                                       <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,结果如图4-29所示。

图4-29 输出人物信息

【代码解析】该代码段第3~6行创建一个对象表示学生,并为之添加了三个属性。第8行输出学生对象的三个属性,第9行使用delete运算符将学生对象的age属性删除。第11、12行试图再次输出学生的三个属性,但age属性已经不存在了,因此输出为undefined。

4.10.8 逗号运算符

逗号运算符使用符号“,”,作用是使其两边的表达式按左到右的顺序被执行,并返回最右边表达式的值。使用语法如下:

        表达式1,表达式2

逗号运算符常用在for循环中。示例如下:

        01  var j = 0;                         // 取0
        02  for( i = 0; i<10; i ++, j++ )      // 循环10遍
        03  {
        04       j *= i;                       // 累乘
        05  }

每次for循环执行到末端时,一般只允许一个表达式被执行。而“,”运算符则可以使两个表达式得到执行,突破了该限制。

4.10.9 函数调用运算符

函数调用运算符“call”,作用于Function对象。主要功能是调用对象的一个方法,并以另一个对象作替换为当前对象,以改变this指针的指向。JavaScript函数和对象方法的调用通常发生于一个运行时上下文中,一般为Global对象上下文。但当前执行上下文可以更改,使用call运算符即可达到目的。语法如下:

        对象名.call( [ thisObj , [ arg1, [ arg2, [ argn, […] ] ] ] ] )

参数说明:

● 对象名:为一个有效的Function对象。

● thisObj:是即将换为当前上下文对象的对象引用,可选,当省略时自动设置为Global对象。

● arg:是传递给Function对象的参数,可选。

使用call运算符可以改变函数执行上下文,这是个特性在一些特殊场合非常有用,下面举例说明以加深理解。

【范例4-26】现有两个学生对象,他们拥有值不相同的同种属性(姓名和年龄)。要求将学生的姓名和年龄输出,如示例代码4-26所示。

示例代码4-26

        01  <script language="javascript">         // 脚本程序开始
        02  <!--
        03     function showStudentInfo()          // 定义一个函数,用于输出学生信息
        04     {
        05                                         // 输出this指向的对象的name、age成员
        06         document.write( "<li>" + this.name + " " + this.age + "<br>" );
        07     }
        08     function Student( _name, _age )     // 定义Student类的构造函数
        09     {
        10         this.name = _name;               // 添加属性
        11         this.age = _age;
        12     }
        13     var stu1 = new Student( "Tom", 20 );// 创建两个学生类实例
        14     var stu2 = new Student( "Lily", 21 );
        15     showStudentInfo.call( stu1 );       // 不同的上下文中调用showStudentInfo
        16     showStudentInfo.call( stu2 );
        17  -->
        18  </script>                              <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,结果如图4-30所示。

图4-30 学生名字和年龄

【代码解析】该代码段第3~7行定义一个函数,用于输出this指针指向的对象的name和age两个属性。第8~12行定义一个学生类构造函数,用于创建学生对象。第13、14行创建了两个学生对象,第15、16行使用call运算符调用函数showStudentInfo。此时执行上下文分别改变为stu1和stu2,目的是重设函数对象showStudentInfo的this指针的指向。

提示:call运算符提供了一种很好的改变执行上下文的机制,使用它可以做出巧妙的设计,读者请多加练习。

4.10.10 this运算符

“this”严格地说是一个关键字,也可以理解为运算符。面向对象的编程中要引用当前对象, this运算符可以返回当前对象的引用。this通常用在对象构造函数中,用来引用函数对象本身。语法如下:

        this.属性名或方法名

给自定义对象添加属性时,在类构造函数中使用this运算符。例如创建一个汽车类,给汽车添加最大速度和载重属性,代码如下所示。

        01  function Car ( _rateMax, _ carryingCapacity )   // 构造函数
        02  {
        03       this. rateMax = _rateMax;                  // 添加属性:极速
        04       this. carryingCapacity = _carryingCapacity;// 添加属性:最大载重
        05  }

4.11 掌握运算符的优先级

前面的内容讲解了JavaScript中的表达式、操作数和运算符,表达式由运算符和操作数构成。到目前为止,读者所接触过的表达式都比较简单,但表达式可以是很复杂的复合表达式。在一个复杂的表达式中,多个运算符结合在一起,势必会出现计算的先后顺序问题。

JavaScript中的运算符优先级是一套规则。该规则在计算表达式时控制运算符执行的顺序。具有较高优先级的运算符先于较低优先级的运算符得到执行。同等级的运算符按左到右的顺序进行。归纳总结如表4-1所示。

表4-1 运算符优先级(从高到低)

由表4-1可以看出,运算符比较多,记住各运算符的优先级并不容易。因此编程时一般都使用圆括号“()”来决定表达式的计算顺序,示例如下:

        ((A + B)&C)>>3

在这里圆括号意义上完全等同于数学表达式里的圆括号,即括号内的优先级最高,最先得到计算。上述代码执行顺序为:A加上B,再将结果与C做位与运算,最后带符号右移3位。下面举例说明运算符的优先级。

【范例4-27】编程测试“+、-、×、÷”运算符的优先顺序,求表达式“1+2/5-0.1*5”的值并输出,如示例代码4-27所示。

示例代码4-27

        01  <script language="javascript">                          // 脚本程序开始
        02       var result1 = 1+2/5-0.1*5;                          // 默认优先级顺序
        03       var result2 = ((1+2)/5-0.1)*5;                      // 用小括号改变优先级
        04       document.write("<b>运行符优先级</b>");                // 输出标题
        05       document.write("<li>1+2/5-0.1*5=" + result1 );      // 输出表达式1的结果
        06       document.write("<li>((1+2)/5-0.1)*5=" + result2 );  // 输出表达式2的结果
        07  </script>                                               <!--脚本程序结束-->

【运行结果】打开网页运行程序,运算结果如图4-31所示,对比其中两个不同表达式的结果。

图4-31 对比两个表达式的结果

【代码解析】代码段第2、3行分别定义两个算术表达式,第一个表达式使用默认运算符优先级。其运算顺序按JavaScript的规定,顺序为“/、+、*、-”。第二个表达式使用小括号强制改变计算优先级,顺序为“+、/、-、*”。

提示:编程时通常使用小括号决定计算优先级,而不用背优先级表。

4.12 小结

本章讲解了JavaScript中的表达式、操作数、算术运算符、关系运算符和逻辑运算符等内容;介绍了数在计算机中的表示以及如何进行位级运算,使用new运算符可以创建类的对象;删除对象动态添加的属性可以使用delete运算符。

instanceof返回一个布尔值表示该对象是否是某个类的实例,typeof则返回一个对象所属的类型名称。JavaScript运算符种类繁多,各类运算符优先级各不相同,圆括号极大地方便了代码的书写。如果读者对本章内容还有什么疑问,可以参考《JavaScript实例自学手册:通过486个例子掌握Web开发捷径》(电子工业出版社,吴雪)和《完全手册:HTML+CSS+JavaScript实用详解》(电子工业出版社,叶青)等书籍。

4.13 习题

一、常见面试题

1.表达式null === undefined的运算结果是否为真?

【解析】本题考查的是常见表达式的运算,只要掌握了表达式的基本概念,本题不难解答,答案是结果为真。

2.说出JavaScript运算符的种类。

【解析】本题考查的是对JavaScript运算符的掌握程度。

【参考答案】算术运算符、关系运算符、字符串运算符、逻辑运算符、赋值运算符、位运算符等。

二、简答题

1.什么是表达式?它有什么作用?

2.列举出JavaScript中的运算符。

三、综合练习

1.人们在网络上传送敏感信息时通常需要加密处理,以防被他人窃取。现在要求编写一个信息加密解密的应用程序,可以将数据信息加密成不可阅读识别的数据,同时又能将加密后的数据解密还原。

【提示】加密解密可以使用位异或运算实现,因为A与B异或得到C,C与B异或可以得到A。因此B将成为密钥。字符串对象的charCodeAt方法可以取得一个字符的unicode编码,可以对此编码进行加密运算。fromCharCode方法可以将一个unicode编辑还原为字符,因此可以从加密解密后的unicode码串还原字符串。参考代码如下:

        01  <body>                                 <!--文档体-->
        02  <script language="javascript">         // 脚本程序开始
        03  <!--
        04  var msgCoded;                          // 加密后的串
        05  var msgEncoded;                        // 解密后的串
        06  function CodeAndEncode( pkey, date )   // 加密解密函数
        07  {
        08     var codedStr = "";                  // 已加密或解密的字符序列
        09     for( i = 0; i<date.length; i++ )    // 对信息串逐个加密
        10     {
        11           var dateCoded;                // 已加密或解的字符的unicode编码
        12           for( j = 0; j<pkey.length; j++ )
                                                  // 密钥串的每个字符与串中当前字符进行位异或
        13           {
        14               var keyCoded = pkey.charCodeAt( j );
                                                  // 从密钥串中提取一个字符的unicode编码
        15               var dateCoded = date.charCodeAt(i) ^ keyCoded;
                                                  // 异或运算
        16           }
        17         codedStr += String.fromCharCode( dateCoded );
        18     }
        19       return codedStr;                   // 返回信息串
        20  }
        21  function BtnCode_onclick()             // “加密”按钮单击事件处理程序
        22  {
        23     var date = TextArea1.value;         // 提取要加密的文本
        24     var key = Password1.value;          // 提取密钥
        25     msgCoded = CodeAndEncode( key, date );       // 加密
        26     TextArea1.value = msgCoded;                  // 在文本域中显示加密结果
        27  }
        28  function BtnEncode_onclick()
        29  {
        30      var date = TextArea1.value;                 // 提取要解密的文本
        31      var key = Password1.value;                  // 提取密钥
        32      msgEncoded = CodeAndEncode( key, date );    // 解密
        33      TextArea1.value = msgEncoded;               // 在文本域中显示解密后的文本
        34  }
        35  -->
        36  </script>                                       <!--脚本程序结束-->
        37  <!-用户界面,设置一个文本域、一个文本编辑框、两个按钮-->
        38     &nbsp;<textarea id="TextArea1" style="width: 331px; height: 211px"></
            textarea>&nbsp;<br />
        39     密钥:&nbsp;
        40     <input id="Password1" type="password" />&nbsp;
        41     <input id="BtnCode" type="button" value="加密" onclick="return BtnCode_
            onclick()"
        42  style="width: 57px" />
        43     <input id="BtnEncode" style="width: 55px" type="button" value="解密"
        44  onclick="return BtnEncode_onclick()" />
        45  </body>                                         <!--文档体结束-->

【运行结果】打开网页文件运行程序,加密结果如图4-32所示,解密结果如图4-33所示。

图4-32 加密后的结果

图4-33 解密后的结果

2.对数个学生的名字进行排序并输出,排序前的顺序为:“Tom”、“Petter”、“Jim”、“Lily”。

【提示】可以使用数组作为数据的容器,使用本章讲过的in运算符结合for循环遍历数组;再使用关系运算符作字符串升降序比较,参考代码如下:

        01  <script language="javascript">             // 脚本程序开始
        02  <!--
        03     var students = new Array( "Tom", "Petter", "Jim", "Lily" );// 学生名字
        04     document.write( "排序前:" + students );  // 输出排序前的名字序列
        05     for( n in students )                    // 在for语句中使用in运算符遍历数组
        06     {
        07         for( m in students )                 // 逐一比较
        08         {
        09            if( students[n] < students[m] )   // 使用“<”运算会进行升序比较
        10            {
        11               var temp = students[n];        // 交换数组元素内容
        12               students[n] = students[m];
        13               students[m] = temp;
        14            }
        15         }
        16     }
        17     document.write( "<br>" );               // 输出换行
        18     document.write( "排序后:" + students );  // 输出排序后的名字序列
        19  -->
        20  </script>                                  <!--脚本程序结束-->

【运行结果】打开网页文件运行程序,运行结果如图4-34所示。

图4-34 运行结果

四、编程题

1.编一程序计算8*x*x+(x+y)*(3*x-8)的值。

【提示】本题可以设置几个变量,然后按照运算符的优先级进行运算即可。

2.编写一程序计算表达式((( b + c ) * 30 + 70 * ( d-3 ) ) * e)%7的值。

【提示】本题与上题类似,只是需要多设置几个变量,然后即可按照相同方法得到计算结果。