JavaScript高级程序设计(第三版)笔记——第三章

基本概念

一、语法

        ECMAScript 的语法大量借鉴了 C 及其他类 C 语言(如 Java Perl)的语法。

1、区分大小写

        ECMAScript 中的一切(变量、函数名和操作符)都区分大小写。 

2、标识符

        所谓标识符,就是指变量、函数、属性的名字,或者函数的参数。标识符可以是按照下列格式规则组合起来的一或多个字符:
        1、第一个字符必须是一个字母、下划线(_)或一个美元符号($);
        2、其他字符可以是字母、下划线、美元符号或数字。

注意:不能把关键字、保留字、 truefalse null 用作标识符。 

3、注释

        ECMAScript 使用 C 风格的注释,包括单行注释和块级注释。

4、严格模式

        ECMAScript 5 引入了严格模式( strict mode)的概念。严格模式是为 JavaScript 定义了一种不同的解析与执行模型。在严格模式下,解析与执行模型。在严格模式下, ECMAScript 3 中的一些不确定的行为将得到处理,而且对某些不安全的操作也会抛出错误。要在整个脚本中启用严格模式,可以在顶部添加如下代码:
        "use strict";

也可以指定函数在严格模式下执行 。

5、语句

        ECMAScript 中的语句以一个分号结尾;如果省略分号,则由解析器确定语句的结尾,如下例所示:
                var sum = a + b // 即使没有分号也是有效的语句——不推荐
                var diff = a - b; // 有效的语句——推荐

虽然语句结尾的分号不是必需的,但我们建议任何时候都不要省略它。


二、关键字和保留字

        ECMA-262 描述了一组具有特定用途的关键字,这些关键字可用于表示控制语句的开始或结束,或者用于执行特定操作等。按照规则,关键字也是语言保留的,不能用作标识符。以下就是 ECMAScript的全部关键字(带*号上标的是第 5 版新增的关键字):do        try      else         break         with           finally        function      instanceof

                  if        new     void        switch       throw         default      continue      typeofcase   

                  in        for       this         return       while          delete       varcatch       debugger*

        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

注意: let yield 是第 5 版新增的保留字;其他保留字都是第 3 版定义的。

          在实现 ECMAScript 3 JavaScript 引擎中使用关键字作标识符,会导致“Identifier Expected”错误。而使用保留字作标识符可能会也可能不会导致相同的错误,具体取决于特定的引擎。

          第 5 版对使用关键字和保留字的规则进行了少许修改。关键字和保留字虽然仍然不能作为标识符使用,但现在可以用作对象的属性名。一般来说,最好都不要使用关键字和保留字作为标识符和属性名,以便与将来的 ECMAScript 版本兼容。

          除了上面列出的保留字和关键字, ECMA-262 5 版对 eval arguments 还施加了限制。在严格模式下,这两个名字也不能作为标识符或属性名,否则会抛出错误。 


三、变量

        ECMAScript 的变量是松散类型的,所谓松散类型就是可以用来保存任何类型的数据。换句话说,每个变量仅仅是一个用于保存值的占位符而已。

       定义变量时使用var操作符(var是关键字):var message;

       该变量可以用来保存任何值(像这样未经过初始化的变量,会保存一个特殊的值——undefined)

       ECMAScript 也支持直接初始化变量,因此在定义变量的同时就可以设置变量的值 :var message = "hi"; 

      如果在函数中用var创建变量,则变量是一个局部变量(function test(){var message = "hi"; // 局部变量} ),只在函数中起作用,函数执行完成后变量被摧毁。如果想让变量在函数外也能使用,则不用var。(如:function test(){message = "hi"; // 全局变量} ) 
       注意:虽然省略 var 操作符可以定义全局变量,但这也不是我们推荐的做法。因为在局部作用域中定义的全局变量很难维护,而且如果有意地忽略了 var 操作符,也会由于相应变量不会马上就有定义而导致不必要的混乱。给未经声明的变量赋值在严格模式下会导致抛出 ReferenceError 错误。
       可以使用一条语句定义多个变量,只要把每个变量(初始化或不初始化均可)用逗号分隔开即可。


四、数据类型

1、typeof操作符
用来检测给定变量的数据类型。可能的返回值:

        "undefined"——如果这个值未定义;

        "boolean"——如果这个值是布尔值;

        "string"——如果这个值是字符串;

        "number"——如果这个值是数值;

        "object"——如果这个值是对象或 null

        "function"——如果这个值是函数。

对于尚未声明的变量,只能执行一项操作,就是使用typeof操作符检测其数据类型。

2、Undefined类型

在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined。

3、Null类型
       从逻辑角度来看, null 值表示一个空对象指针,而这也正是使用 typeof 操作符检测 null 值时会返回"object"的原因,如下面的例子所示:

                    var car = null;

                    alert( typeof car );     // "object 

       如果定义的变量准备在将来用于保存对象,那么最好将该变量初始化为 null 而不是其他值。这样一来,只要直接检查 null 值就可以知道相应的变量是否已经保存了一个对象的引用,如下面的例子所示:

                    if ( car != null )  { // car 对象执行某些操作 }

       实际上, undefined 值是派生自 null 值的,因此 ECMA-262 规定对它们的相等性测试要返回 true

                    alert( null == undefined );   //true
4、Boolean类型

该类型有两个字面值: true false

注意: Boolean 类型的字面值 true false 是区分大小写的。

下表给出了各种数据类型及其对应的转换规则:

数据类型 转换为true的值 转换为false的值
Boolean true

false

String 任何非空字符串 “”(空字符串)
Number 任何非零数字值(包括无穷大) 0和NaN
Object 任何对象 null
Undefined n/a (not applicable 不适用) undefined
5、Number类型

这种类型使用 IEEE754 格式来表示整数和浮点数值(浮点数值在某些语言中也被称为双精度数值)。 

       十进制 。
      八进制字面值的第一位必须是零( 0),然后是八进制数字序列( 07)。如果字面值中的数值超出了范围,那么前导零将被忽略,后面的数值将被当作十进制数值解析。

      十六进制字面值的前两位必须是 0x,后跟任何十六进制数字( 09 AF)。其中,字母 AF不区分大小写。 

      在进行算术计算时,所有以八进制和十六进制表示的数值最终都将被转换成十进制数值。

  • 浮点数值

        以下是浮点数值的几个例子:
        var floatNum1 = 1.1;
        var floatNum2 = 0.1;
        var floatNum3 = .1;     // 有效,但不推荐

       如果小数点后面没有跟任何数字,或者浮点数值本身表示的就是该值那么这个数值就可以作为整数值来保存。如下例子所示:

        var floatNum1 = 1.  ;   // 小数点后面没有数字——解析为 1
        var floatNum2 = 10.0 ;   // 整数——解析为 10

       对于那些极大或极小的数值,可以用 e 表示法(即科学计数法)表示的浮点数值表示。用 e 表示法表示的数值等于表示的数值等于 e 前面的数值乘以 10 的指数次幂。 

       在默认情况下, ECMASctipt 会将那些小数点后面带有 6 个零以上的浮点数值转换为以 e 表示法表示的数值。(例如,表示的数值(例如, 0.0000003 会被转换成 3e-7

  • 数值范围

       ECMAScript 能够表示的最小数值保存在Number.MIN_VALUE 中——在大多数浏览器中,这个值是 5e-324;能够表示的最大数值保存在Number.MAX_VALUE 中——在大多数浏览器中,这个值是 1.7976931348623157e+308。如果某次计算的结果得到了一个超出结果得到了一个超出 JavaScript 数值范围的值,那么这个数值将被自动转换成特殊的 Infinity 值(无穷大,包括-Infinity和Infinity)。

       可以使用 isFinite()函数来确定一个数值是不是有穷的。

  • NaN

       即非数值( Not a Number)是一个特殊的数值,这个数值用于表示一个本来要返回数值的操作数未返回数值的情况(这样就不会抛出错误了)。ECMAScript 中,任何数值除以 0 会返回 NaN(但实际上只有 0 除以 0 才会返回 NaN,正数除以 0 返回 Infinity,负数除以 0 返回-Infinity,因此不会影响其他代码的执行。首先,任何涉及 NaN 的操作(例如 NaN/10)都会返回 NaN,这个特点在多步计算中有可能导致问题。其次,NaN 与任何值都不相等,包括 NaN 本身。 

       可以使用isNaN()函数来确定一个参数是否“不是数值”。 
       alert(isNaN(NaN));   //true
       alert(isNaN(10));   //false
10 是一个数值)
       alert(isNaN("10"));   //false(可以被转换成数值 10
       alert(isNaN("blue"));   //true(不能转换成数值)
       alert(isNaN(true));   //false(可以被转换成数值 1


  • 数值转换

       3 个函数可以把非数值转换为数值: Number()(用于任何数据类型parseInt()parseFloat()(用于把字符串转换成数值

      Number()函数的转换规则如下:
              如果是 Boolean 值, true false 将分别被转换为 1 0
              如果是数字值,只是简单的传入和返回。
              如果是 null 值,返回 0
              如果是 undefined,返回 NaN
              如果是字符串,遵循下列规则:
              1、如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即"011"会变成 11(注意:前导的零被忽略了);
              2、如果字符串中包含有效的浮点格式,如"1.1",则将其转换为对应的浮点数值(同样,也会忽略前导零);
               3、如果字符串中包含有效的十六进制格式,例如"0xf",则将其转换为相同大小的十进制整数值;
               4、如果字符串是空的(不包含任何字符),则将其转换为 0
               5、如果字符串中包含除上述格式之外的字符,则将其转换为 NaN

              如果是对象,则调用对象的 valueOf()方法,然后依照前面的规则转换返回的值。如果转换的结果是 NaN,则调用对象的 toString()方法,然后再次依照前面的规则转换返回的字符串值。

                var num1 = Number("Hello world!");   //NaN
                var num2 = Number("");   //0
                var num3 = Number("000011");   //11

                var num4 = Number(true);   //1

        parseInt()函数的转换规则,下面给出一些例子:
                var num1 = parseInt("1234blue");   // 1234
                var num2 = parseInt("");   // NaN
                var num3 = parseInt("0xA");   // 10
(十六进制数)
                var num4 = parseInt(22.5);   // 22
                var num5 = parseInt("070");   // 56
(八进制数)
                var num6 = parseInt("70");   // 70(十进制数)

                var num7 = parseInt("0xf");   // 15(十六进制数)

        可以为这个函数提供第二个参数,表示是多少进制的数,例子如下:

                var num = parseInt("0xAF", 16);   //175
        实际上,如果指定了 16 作为第二个参数,字符串可以不带前面的"0x",如下所示:
                var num1 = parseInt("AF", 16);   //175
                var num2 = parseInt("AF");   //NaN

        指定基数会影响到转换的输出结果。例如:
                var num1 = parseInt("10", 2);   //2 (按二进制解析)
                var num2 = parseInt("10", 8);   //8 (按八进制解析)
                var num3 = parseInt("10", 10);   //10 (按十进制解析)

                var num4 = parseInt("10", 16);   //16 (按十六进制解析)

        以下是使用 parseFloat()转换数值的几个典型示例:
                var num1 = parseFloat("1234blue");   //1234 (整数)
                var num2 = parseFloat("0xA");   //0
                var num3 = parseFloat("22.5");   //22.5
                var num4 = parseFloat("22.34.5");   //22.34(只有第一个小数点是有效的)
                var num5 = parseFloat("0908.5");   //908.5
                var num6 = parseFloat("3.125e7");   //31250000

6、String类型

        String 类型用于表示由零个或多个 16 Unicode 字符组成的字符序列,即字符串。字符串可以由双引号(")或单引号(')表示,因此下面两种字符串的写法都是有效的:
                var firstName = "Nicholas";

                var lastName = 'Zakas';

  • 字符字面量

String 数据类型包含一些特殊的字符字面量,也叫转义序列,用于表示非打印字符,或者具有其他用途的字符。这些字符字面量如下表所示:

JavaScript高级程序设计(第三版)笔记——第三章_第1张图片

  • 字符串的特点

字符串是不可变的,字符串一旦创建,它们的值就不能改变。

  • 转换为字符串

toString()方法返回相应值的字符串表现。
        var age = 11;
        var ageAsString = age.toString(); //
字符串"11"
        var found = true;

        var foundAsString = found.toString(); // 字符串"true" 

        数值、布尔值、对象和字符串值(每个字符串也都有一个 toString()方法,该方法返回字符串的一个副本)都有 toString()方法。但 null undefined 值没有这个方法。 

        toString()可以输出以二进制、八进制、十六进制,乃至其他任意有效进制格式表示的字符串值。下面给出几个例子:

        var num = 10;
        alert(num.toString());   // "10"
        alert(num.toString(2));   // "1010"
        alert(num.toString(8));   // "12"
        alert(num.toString(10));   // "10"
        alert(num.toString(16));   // "a"


       在不知道要转换的值是不是 null undefined 的情况下,还可以使用转型函数 String(),这个函数能够将任何类型的值转换为字符串。 String()函数遵循下列转换规则:
                1、如果值有 toString()方法,则调用该方法(没有参数)并返回相应的结果;
                2、如果值是 null,则返回"null"

                3、如果值是 undefined,则返回"undefined"

       下面再看几个例子:
                var value1 = 10;
                var value2 = true;
                var value3 = null;
                var value4;
                alert(String(value1));   // "10"
                alert(String(value2));   // "true"
                alert(String(value3));   // "null"
                alert(String(value4));   // "undefined"


7、Object类型

创建 Object 类型的实例并为其添加属性和(或)方法,就可以创建自定义对象,如下所示:
        var o = new Object();

Object 的每个实例都具有下列属性和方法。
        1、constructor:保存着用于创建当前对象的函数。对于前面的例子而言,构造函数( constructor就是 Object()
        2、hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在。其中,作为参数的属性名( propertyName)必须以字符串形式指定(例如: o.hasOwnProperty("name"))。
        3、isPrototypeOf(object):用于检查传入的对象是否是传入对象的原型(第 5 章将讨论原型)。
        4、propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用 for-in 语句(本章后面将会讨论)来枚举。与 hasOwnProperty()方法一样,作为参数的属性名必须以字符串形式指定。
        5、toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
        6、toString():返回对象的字符串表示。
        7、valueOf():返回对象的字符串、数值或布尔值表示。通常与 toString()方法的返回值相同。

由于在 ECMAScript Object 是所有对象的基础,因此所有对象都具有这些基本的属性和方法。

五、操作符
1、一元操作符

只能操作一个值的操作符叫做一元操作符

  • 递增和递减操作符

        i++、++i、i--、--i。

        在应用于不同的值时,递增和递减操作符遵循下列规则。
        1、在应用于一个包含有效数字字符的字符串时,先将其转换为数字值,再执行加减 1 的操作。字符串变量变成数值变量。
        2、在应用于一个不包含有效数字字符的字符串时,将变量的值设置为 NaN。字符串变量变成数值变量。
        3、在应用于布尔值 false 时,先将其转换为 0 再执行加减 1 的操作。布尔值变量变成数值变量。
        4、在应用于布尔值 true 时,先将其转换为 1 再执行加减 1 的操作。布尔值变量变成数值变量。
        5、在应用于浮点数值时,执行加减 1 的操作。

        6、在应用于对象时,先调用对象的 valueOf()方法(第 5 章将详细讨论)以取得一个可供操作的值。然后对该值应用前述规则。如果结果是 NaN,则在调用 toString()方法后再应用前述规则。对象变量变成数值变量。

        以下示例展示了上面的一些规则:

                var s1 = "2";
                var s2 = "z";
                var b = false;
                var f = 1.1;

                var o = {  valueOf: function() {  return -1;  }  };

                s1++;  // 值变成数值 3
                s2++;  //
值变成 NaN
                b ++;  //
值变成数值 1
                f  - - ;  //
值变成 0.10000000000000009(由于浮点舍入错误所致)

                o - - ;  // 值变成数值-2

  • 一元加和减操作符

        在对非数值应用一元加操作符时,该操作符会像 Number()转型函数一样对这个值执行转换。换句话说,布尔值 false true 将被转换为 0 1,字符串值会被按照一组特殊的规则进行解析,而对象是先调用它们的 valueOf()和(或) toString()方法,再转换得到的值。
        下面的例子展示了对不同数据类型应用一元加操作符的结果:
                var s1 = "01";
                var s2 = "1.1";
                var s3 = "z";
                var b = false;
                var f = 1.1;

                var o = {valueOf: function() {return -1;}};

                s1 = +s1;   // 值变成数值 1
                s2 = +s2;   //
值变成数值 1.1
                s3 = +s3;   //
值变成 NaN
                b  = + b ;   //
值变成数值 0
                f   = + f  ;   //
值未变,仍然是 1.1

                o  = + o ;   // 值变成数值-1 

一元减操作符主要用于表示负数。

2、位操作符

位操作符用于在最基本的层次上,即按内存中表示数值的位来操作数值。

  • 按位非(NOT)

按位非操作符由一个波浪线( ~)表示,执行按位非的结果就是返回数值的反码。下面看一个例子:
        var num1 = 25;   // 二进制 00000000000000000000000000011001
        var num2 = ~num1;   //
二进制 11111111111111111111111111100110
        alert(num2);   // -26

这里对 25 执行按位非操作,结果得到了-26。这也验证了按位非操作的本质:操作数的负值减 1

  • 按位与(AND)

按位与操作符由一个和号字符( &)表示,它有两个操作符数。从本质上讲,按位与操作就是将两个数值的每一位对齐,然后根据下表中的规则,对相同位置上的两个数执行 AND 操作:

JavaScript高级程序设计(第三版)笔记——第三章_第2张图片

下面看一个对 25 3 执行按位与操作的例子:
        var result = 25 & 3;
        alert(result);   //1

可见,对 25 3 执行按位与操作的结果是 1。为什么呢?请看其底层操作:
         25 =  0000 0000 0000 0000 0000 0000 0001 1001
          3  =  0000 0000 0000 0000 0000 0000 0000 0011
        --------------------------------------------------------

      AND = 0000 0000 0000 0000 0000 0000 0000 0001

  • 按位或(OR)

按位或操作符由一个竖线符号( |)表示,同样也有两个操作数。按位或操作遵循下面这个真值表。

JavaScript高级程序设计(第三版)笔记——第三章_第3张图片

如果在前面按位与的例子中对 25 3 执行按位或操作,则代码如下所示:
        var result = 25 | 3;
        alert(result); //27

25 3 按位或的结果是 27
        25  = 0000 0000 0000 0000 0000 0000 0001 1001
        3    = 0000 0000 0000 0000 0000 0000 0000 0011
      ---------------------------------------------------------

        OR = 0000 0000 0000 0000 0000 0000 0001 1011 

  • 按位异或(XOR)

按位异或操作符由一个插入符号( ^)表示,也有两个操作数。以下是按位异或的真值表。
JavaScript高级程序设计(第三版)笔记——第三章_第4张图片

25 3 执行按位异或操作的代码如下所示:
        var result = 25 ^ 3;
        alert(result); //26

25 3 按位异或的结果是 26,其底层操作如下所示:
         25   = 0000 0000 0000 0000 0000 0000 0001 1001
          3    = 0000 0000 0000 0000 0000 0000 0000 0011
        ---------------------------------------------------------

        XOR = 0000 0000 0000 0000 0000 0000 0001 1010

  • 左移

左移操作符由两个小于号( <<)表示,这个操作符会将数值的所有位向左移动指定的位数。例如,如果将数值 2(二进制码为 10)向左移动 5 位,结果就是 64(二进制码为 1000000),代码如下所示:
        var oldValue = 2;   // 等于二进制的 10
        var newValue = oldValue << 5;   //
等于二进制的 1000000,十进制的 64
左移不会影响操作数的符号位。

  • 有符号的右移

有符号的右移操作符由两个大于号( >>)表示,这个操作符会将数值向右移动,但保留符号位(即正负号标记)。有符号的右移操作与左移操作恰好相反,即如果将 64 向右移动 5 位,结果将变回 2
        var oldValue = 64;   // 等于二进制的 1000000

        var newValue = oldValue >> 5;   // 等于二进制的 10 ,即十进制的 2

  • 无符号的右移

无符号右移操作符由 3 个大于号( >>>)表示,这个操作符会将数值的所有 32 位都向右移动。对正数来说,无符号右移的结果与有符号右移相同。但对于负数来说不一样,如下面的例子所示:
        var oldValue = -64; // 等于二进制的 11111111111111111111111111000000
        var newValue = oldValue >>> 5; // 等于十进制的 134217726


3、布尔操作符
  • 逻辑非

        逻辑非操作符由一个叹号(! )表示无论这个值是什么数据类型,这个操作符都会返回一个布尔值。逻辑非操作符首先会将它的操作数转换为一个布尔值,然后再对其求反。也就是说,逻辑非操作符遵循下列规则:
        1、如果操作数是一个对象,返回 false
        2、如果操作数是一个空字符串,返回 true
        3、如果操作数是一个非空字符串,返回 false
        4、如果操作数是数值 0,返回 true
        5、如果操作数是任意非 0 数值(包括 Infinity),返回 false
        6、如果操作数是 null,返回 true
        7、如果操作数是 NaN,返回 true
        8、如果操作数是 undefined,返回 true
下面几个例子展示了应用上述规则的结果:
        alert(!false);     // true
        alert(!"blue");  // false
        alert(!0);          // true
        alert(!NaN);    // true
        alert(!"");         // true

        alert(!12345);  // false

  • 逻辑与

逻辑与操作符由两个和号( &&)表示,有两个操作数,如下面的例子所示:

        var result = true && false;

逻辑与的真值表如下:

JavaScript高级程序设计(第三版)笔记——第三章_第5张图片

        逻辑与操作可以应用于任何类型的操作数,而不仅仅是布尔值。在有一个操作数不是布尔值的情况下,逻辑与操作就不一定返回布尔值;此时,它遵循下列规则:
                1、如果第一个操作数是对象,则返回第二个操作数;
                2、如果第二个操作数是对象,则只有在第一个操作数的求值结果为 true 的情况下才会返回该对象;
                3、如果两个操作数都是对象,则返回第二个操作数;
                4、如果有一个操作数是 null,则返回 null
                5、如果有一个操作数是 NaN,则返回 NaN
                6、如果有一个操作数是 undefined,则返回 undefined
逻辑与操作属于短路操作,即如果第一个操作数能够决定结果,那么就不会再对第二个操作数求值。
对于逻辑与操作而言,如果第一个操作数是
false,则无论第二个操作数是什么值,结果都不再可能是
true 了。来看下面的例子:
                var found = true;
                var result = (found && someUndefinedVariable);   //
这里会发生错误
                alert(result);   // 这一行不会执行

如果像下面这个例中一样,将 found 的值设置为 false,就不会发生错误了:
                var found = false;
                var result = (found && someUndefinedVariable);   // 不会发生错误(由于短路操作后面一项不执行,则不会报错)
                alert(result);   // 会执行( "false"

  • 逻辑或

逻辑或操作符由两个竖线符号( ||)表示,有两个操作数,如下面的例子所示:
        var result = true || false;

逻辑或的真值表如下:

JavaScript高级程序设计(第三版)笔记——第三章_第6张图片

        与逻辑与操作相似,如果有一个操作数不是布尔值,逻辑或也不一定返回布尔值;此时,它遵循下列规则:
                1、如果第一个操作数是对象,则返回第一个操作数;
                2、如果第一个操作数的求值结果为 false,则返回第二个操作数;
                3、如果两个操作数都是对象,则返回第一个操作数;
                4、如果两个操作数都是 null,则返回 null
                5、如果两个操作数都是 NaN,则返回 NaN
                6、如果两个操作数都是 undefined,则返回 undefined
        与逻辑与操作符相似,逻辑或操作符也是短路操作符。也就是说,如果第一个操作数的求值结果为
true,就不会对第二个操作数求值了。下面看一个例子:

                var found = true;
                var result = (found || someUndefinedVariable);   // 不会发生错误
                alert(result); // 会执行( "true"

4、乘性操作符
        在操作数为非数值的情况下会执行自动的类型转换。如果参与乘性计算的某个操作数不是数值,后台会先使用 Number()转型函数将其转换为数值。也就是说,空字符串将被当作0,布尔值 true 将被当作 1 。

  • 乘法

乘法操作符由一个星号( *)表示,用于计算两个数值的乘积。其语法类似于 C,如下面的例子所示:
        var result = 34 * 56;
在处理特殊值的情况下,乘法操作符遵循下列特殊的规则:
        1、如果操作数都是数值,执行常规的乘法计算,即两个正数或两个负数相乘的结果还是正数,而如果只有一个操作数有符号,那么结果就是负数。如果乘积超过了 ECMAScript 数值的表示范围,则返回 Infinity -Infinity
        2、如果有一个操作数是 NaN,则结果是 NaN
        3、如果是 Infinity 0 相乘,则结果是 NaN
        4、如果是 Infinity 与非 0 数值相乘,则结果是 Infinity -Infinity,取决于有符号操作数的符号;
        5、如果是 Infinity Infinity 相乘,则结果是 Infinity
        6、如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。

  • 除法

除法操作符由一个斜线符号( /)表示,执行第二个操作数除第一个操作数的计算,如下面的例子所示:
        var result = 66 / 11;
与乘法操作符类似,除法操作符对特殊的值也有特殊的处理规则。这些规则如下:
        1、如果操作数都是数值,执行常规的除法计算,即两个正数或两个负数相除的结果还是正数,而如果只有一个操作数有符号,那么结果就是负数。如果商超过了 ECMAScript 数值的表示范围,则返回 Infinity -Infinity
        2、如果有一个操作数是 NaN,则结果是 NaN
        3、如果是 Infinity Infinity 除,则结果是 NaN
        4、如果是零被零除,则结果是 NaN
        5、如果是非零的有限数被零除,则结果是 Infinity -Infinity,取决于有符号操作数的符号;
        6、如果是 Infinity 被任何非零数值除,则结果是 Infinity -Infinity,取决于有符号操作数的符号;
        7、如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。

  • 求模

求模(余数)操作符由一个百分号( %)表示,用法如下:
        var result = 26 % 5;   // 等于 1
与另外两个乘性操作符类似,求模操作符会遵循下列特殊规则来处理特殊的值:
        1、如果操作数都是数值,执行常规的除法计算,返回除得的余数;
        2、如果被除数是无穷大值而除数是有限大的数值,则结果是 NaN
        3、如果被除数是有限大的数值而除数是零,则结果是 NaN
        4、如果是 Infinity Infinity 除,则结果是 NaN
        5、如果被除数是有限大的数值而除数是无穷大的数值,则结果是被除数;
        6、如果被除数是零,则结果是零;
        7、如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。

5、加性操作符

  • 加法

加法操作符( +)的用法如下所示:
        var result = 1 + 2;
如果两个操作符都是数值,执行常规的加法计算,然后根据下列规则返回结果:
        1、如果有一个操作数是 NaN,则结果是 NaN
        2、如果是 Infinity Infinity,则结果是 Infinity
        3、如果是-Infinity -Infinity,则结果是-Infinity
        4、如果是 Infinity -Infinity,则结果是 NaN
        5、如果是+0 +0,则结果是+0
        6、如果是-0 加-0,则结果是-0
        7、如果是+0 加-0,则结果是+0
不过,如果有一个操作数是字符串,那么就要应用如下规则:
        1、如果两个操作数都是字符串,则将第二个操作数与第一个操作数拼接起来;
        2、如果只有一个操作数是字符串,则将另一个操作数转换为字符串,然后再将两个字符串拼接起来。
如果有一个操作数是对象、数值或布尔值,则调用它们的
toString()方法取得相应的字符串值,然后再应用前面关于字符串的规则。对于 undefined null,则分别调用 String()函数并取得字符串"undefined""null"

下面来举几个例子:
        var result1 = 5 + 5;   // 两个数值相加
        alert(result1); // 10

        var result2 = 5 + "5";   // 一个数值和一个字符串相加
        alert(result2); // "55"

再来看一个例子:
        var num1 = 5;
        var num2 = 10;
        var message = "The sum of 5 and 10 is " + num1 + num2;
        alert(message); // "The sum of 5 and 10 is 510"

        var num1 = 5;
        var num2 = 10;
        var message = "The sum of 5 and 10 is " + (num1 + num2);
        alert(message); //"The sum of 5 and 10 is 15"

        每个加法操作是独立执行的,上面的先执行字符串+num1则变成了一个有两个字符串拼接成的字符串,再去+num2,同理也变成了拼接成的字符串。下面的先执行num1+num2,按照数学运算计算,最后再和前面的字符串拼接。

  • 减法

减法操作符(-)是另一个极为常用的操作符,其用法如下所示:
        var result = 2 - 1;
与加法操作符类似, ECMAScript 中的减法操作符在处理各种数据类型转换时,同样需要遵循一些特殊规则,如下所示:
        1、如果两个操作符都是数值,则执行常规的算术减法操作并返回结果;
        2、如果有一个操作数是 NaN,则结果是 NaN
        3、如果是 Infinity Infinity,则结果是 NaN
        4、如果是-Infinity -Infinity,则结果是 NaN
        5、如果是 Infinity -Infinity,则结果是 Infinity
        6、如果是-Infinity Infinity,则结果是-Infinity
        7、如果是+0 +0,则结果是+0
        8、如果是+0 减 -0,则结果是 -0
        9、如果是0 0,则结果是+0
        10、如果有一个操作数是字符串、布尔值、 null undefined,则先在后台调用 Number()函数将其转换为数值,然后再根据前面的规则执行减法计算。如果转换的结果是 NaN,则减法的结果就是 NaN
        11、如果有一个操作数是对象,则调用对象的 valueOf()方法以取得表示该对象的数值。如果得到的值是 NaN,则减法的结果就是 NaN。如果对象没有 valueOf()方法,则调用其 toString()方法并将得到的字符串转换为数值。
        下面几个例子展示了上面的规则:
        var result1 = 5 - true;    // 4,因为 true 被转换成了 1
        var result2 = NaN - 1;   // NaN
        var result3 = 5 - 3;        // 2
        var result4 = 5 - "";       // 5
,因为"" 被转换成了 0
        var result5 = 5 - "2";     // 3
,因为"2"被转换成了 2
        var result6 = 5 - null;    // 5
,因为 null 被转换成了 0

6、关系操作符

ECMAScript 中的其他操作符一样,当关系操作符的操作数使用了非数值时,也要进行数据转换或完成某些奇怪的操作。以下就是相应的规则。
        1、如果两个操作数都是数值,则执行数值比较。
        2、如果两个操作数都是字符串,则比较两个字符串对应的字符编码值。
        3、如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较。
        4、如果一个操作数是对象,则调用这个对象的 valueOf()方法,用得到的结果按照前面的规则执行比较。如果对象没有 valueOf()方法,则调用 toString()方法,并用得到的结果根据前面的规则执行比较。

        5、如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较。

        在比较字符串时,实际比较的是两个字符串中对应位置的每个字符的字符编码值。经过这么一番比较之后,再返回一个布尔值。由于大写字母的字符编码全部小于小写字母的字符编码,因此我们就会看到如下的奇怪现象:

        var result = "Brick" < "alphabet"; //true (原因是字母 B 的字符编码为 66,而字母 a 的字符编码是 97

       如果要真正按字母表顺序比较字符串,就必须把两个操作数转换为相同的大小写形式(全部大写或全部小写),然后再执行比较,如下所示:

        var result = "Brick".toLowerCase() < "alphabet".toLowerCase(); //false

7、相等操作符

相等不相等——先转换再比较, 全等不全等——仅比较而不转换。 

  • 相等和不相等

        ECMAScript 中的相等操作符由两个等于号( ==)表示,如果两个操作数相等,则返回 true。而不相等操作符由叹号后跟等于号( !=)表示,如果两个操作数不相等,则返回 true。这两个操作符都会先转换操作数(通常称为强制转型),然后再比较它们的相等性。
        在转换不同的数据类型时,相等和不相等操作符遵循下列基本规则:
        1、如果有一个操作数是布尔值,则在比较相等性之前先转换为数值——false 转换为 0true 转换为 1
        2、如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值;
        3、如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法,用得到的基本类型值按照前面的规则进行比较;

这两个操作符在进行比较时则要遵循下列规则。
        1、null undefined 是相等的。
        2、要比较相等性之前,不能将 null undefined 转换成其他任何值。
        3、如果有一个操作数是 NaN,则相等操作符返回 false,而不相等操作符返回 true。重要提示:即使两个操作数都是 NaN,相等操作符也返回 false;因为按照规则, NaN 不等于 NaN
        4、如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回 true;否则,返回 false

下表列出了一些特殊情况及比较结果:

JavaScript高级程序设计(第三版)笔记——第三章_第7张图片

  • 全等和不全等

        全等操作符由 3 个等于号( ===)表示,它只在两个操作数未经转换就相等的情况下返回 true,如下面的例子所示:
                var result1 = ("55" == 55);     //true,因为转换后相等
                var result2 = ("55" === 55);  //false,因为不同的数据类型不相等 

        不全等操作符由一个叹号后跟两个等于号( !==)表示,它在两个操作数未经转换就不相等的情况下返回 true。例如:
                var result1 = ("55" != 55);     //false,因为转换后相等
                var result2 = ("55" !== 55);  //true,因为不同的数据类型不相等 

8、条件操作符

        条件操作符遵循与 Java 中的条件操作符相同的语法形式,如下面的例子所示:

        variable = boolean_expression ? true_value : false_value;

        本质上,这行代码的含义就是基于对 boolean_expression 求值的结果,决定给变量 variable赋什么值。如果求值结果为 true,则给变量 variable true_value 值;如果求值结果为 false,则给变量 variable false_value 值。

        再看一个例子:var max = (num1 > num2) ? num1 : num2;

        在这个例子中, max 中将会保存一个最大的值。这个表达式的意思是:如果 num1 大于 num2(关系表达式返回 true),则将 num1 的值赋给 max;如果 num1 小于或等于 num2(关系表达式返回 false),则将 num2 的值赋给 max
9、赋值操作符

简单的赋值操作符由等于号( =)表示,作用是把右侧的值赋给左侧的变量,如下面的例子所示:

        var num = 10;
如果在等于号( =)前面再添加乘性操作符、加性操作符或位操作符,就可以完成复合赋值操作。这种复合赋值操作相当于是对下面常规表达式的简写形式:
        var num = 10;
        num = num + 10;
其中的第二行代码可以用一个复合赋值来代替:
        var num = 10;
        num += 10;
每个主要算术操作符(以及个别的其他操作符)都有对应的复合赋值操作符。这些操作符如下所示:
1、乘/赋值( *=);
2、除/赋值( /=);
3、模/赋值( %=);
4、加/赋值( +=);
5、减/赋值( =);
6、左移/赋值( <<=);
7、有符号右移/赋值( >>=);
8、无符号右移/赋值( >>>=)。

10、逗号操作符

使用逗号操作符可以在一条语句中执行多个操作,如下面的例子所示:

        var num1=1, num2=2, num3=3;
逗号操作符多用于声明多个变量;但除此之外,逗号操作符还可以用于赋值。在用于赋值时,逗号操作符总会返回表达式中的最后一项,如下面的例子所示:
        var num = (5, 1, 4, 8, 0);   // num 的值为 0

六、语句

1、if语句

        以下是 if 语句的语法:  if  ( condition )   statement1   else   statement2

其中的 condition(条件)可以是任意表达式;而且对这个表达式求值的结果不一定是布尔值。ECMAScript 会自动调用 Boolean()转换函数将这个表达式的结果转换为一个布尔值。如果对 condition求值的结果是 true,则执行 statement1(语句 1),如果对 condition 求值的结果是 false,则执行 statement2(语句 2)。而且这两个语句既可以是一行代码,也可以是一个代码块(以一对花括号括起来的多行代码)。
请看下面的例子。
        if (i > 25)
                alert("Greater than 25."); // 单行语句
        else {
                alert("Less than or equal to 25."); // 代码块中的语句
        }

2、do-while语句

        do-while 语句是一种后测试循环语句,即只有在循环体中的代码执行之后,才会测试出口条件。换句话说,在对条件表达式求值之前,循环体内的代码至少会被执行一次。至少执行一次,以下是 do-while 语句的
        语法:
        do {
                statement

        } while (expression);

        下面是一个示例:

        var i = 0;
        do {
                i += 2;
        } while (i < 10);
        alert(i);
 
3、while语句

        while 语句属于前测试循环语句, 也就是说, 在循环体内的代码被执行之前,就会对出口条件求值。因此,循环体内的代码有可能永远不会被执行。以下是 while 语句的语法:

        while(expression) statement

        下面是一个示例:

        var i = 0;
        while (i < 10) {

                i += 2;
        }
 
4、for语句

        for 语句也是一种前测试循环语句,但它具有在执行循环之前初始化变量和定义循环后要执行的代码的能力。以下是 for 语句的语法:

        for (initialization; expression; post-loop-expression) statement

        下面是一个示例:

        var count = 10;
        for (var i = 0; i < count; i++){
                alert(i);
        }
 
5、for-in语句

        for-in 语句是一种精准的迭代语句,可以用来枚举对象的属性。以下是 for-in 语句的语法:

        for (property in expression) statement

        下面是一个示例:

        for (var propName in window) {
                document.write(propName);
        }

        如果表示要迭代的对象的变量值为 null undefinedfor-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 语句虽然也是立即退出循环,但退出循环后会从循环的顶部继续执行。例子如下:
        var num = 0;
        for (var i=1; i < 10; i++) {
                if (i % 5 == 0) {
                        break;
                }
                num++;
        }
        alert(num);     //4

        var num = 0;
        for (var i=1; i < 10; i++) {
                if (i % 5 == 0) {
                        continue;
                }
                num++;
        }
        alert(num); //8

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;
                }
 

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
        }

注意:switch 语句在比较值时使用的是全等操作符,因此不会发生类型转换(如:字符串"10"不等于数值 10)。

七、函数

ECMAScript 中的函数使用 function 关键字来声明,后跟一组参数以及函数体。函数的基本语法如下所示:
        function functionName(arg0, arg1,...,argN) {
                statements
        }
以下是一个函数示例:
        function sayHi(name, message) {
                alert("Hello " + name + "," + message);

        }

        ECMAScript 中的函数在定义时不必指定是否返回值。实际上,任何函数在任何时候都可以通过return 语句后跟要返回的值来实现返回值。请看下面的例子:
        function sum(num1, num2) {
                return num1 + num2;
        }

        函数在执行完 return 语句之后停止并立即退出。因此,位于 return 语句之后的任何代码都永远不会执行。 

严格模式对函数有一些限制:

        1、不能把函数命名为 eval arguments
        2、不能把参数命名为 eval arguments
        3、不能出现两个命名参数同名的情况。
如果发生以上情况,就会导致语法错误,代码无法执行。


1、理解参数

        ECMAScript 函数不介意传递进来多少个参数,也不在乎传进来参数是什么数据类型。 ECMAScript 中的参数在内部是用一个数组来表示的 。在函数体内可以通过 arguments 对象来访问这个参数数组,从而获取传递给函数的每一个参数。

        arguments 对象只是与数组类似(它并不是 Array 的实例),因为可以使用方括号语法访问它的每一个元素(即第一个元素是 arguments[0],第二个元素是 argumetns[1],以此类推),使length 属性来确定传递进来多少个参数。在前面的例子中, sayHi()函数的第一个参数的名字叫name,而该参数的值也可以通过访问 arguments[0]来获取。因此,那个函数也可以像下面这样重写,即不显式地使用命名参数:
        function sayHi() {
                alert("Hello " + arguments[0] + "," + arguments[1]);
        }

        ECMAScript 函数的一个重要特点:命名的参数只提供便利,但不是必需的。

        通过访问 arguments 对象的 length 属性可以获知有多少个参数传递给了函数。下面这个函数会在每次被调用时,输出传入其中的参数个数:
        function howManyArgs() {
                alert(arguments.length);
        }
        howManyArgs("string", 45);    //2
        howManyArgs();    //0

        howManyArgs(12);    //1

另一个与参数相关的重要方面,就是 arguments 对象可以与命名参数一起使用,如下面的例子所示:

        function doAdd(num1, num2) {
                if(arguments.length == 1) {
                        alert(num1 + 10);
                } else if (arguments.length == 2) {
                        alert(arguments[0] + num2);
                }

        }

2、没有重载

        ECMAScript 函数不能像传统意义上那样实现重载。而在其他语言(如 Java)中,可以为一个函数编写两个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可。如前所述, ECMAScirpt函数没有签名,因为其参数是由包含零或多个值的数组来表示的。而没有函数签名,真正的重载是不可能做到的。

        如果在 ECMAScript 中定义了两个名字相同的函数,则该名字只属于后定义的函数。请看下面的例子:
        function addSomeNumber(num){
                return num + 100;
        }
        function addSomeNumber(num) {
                return num + 200;
        }
        var result = addSomeNumber(100);    //300

八、小结

        JavaScript 的核心语言特性在 ECMA-262 中是以名为 ECMAScript 的伪语言的形式来定义的。ECMAScript 中包含了所有基本的语法、操作符、数据类型以及完成基本的计算任务所必需的对象,但没有对取得输入和产生输出的机制作出规定。理解 ECMAScript 及其纷繁复杂的各种细节,是理解其在Web 浏览器中的实现——JavaScript 的关键。目前大多数实现所遵循的都是 ECMA-262 3 版,但很多也已经着手开始实现第 5 版了。以下简要总结了 ECMAScript 中基本的要素。

  • ECMAScript 中的基本数据类型包括 UndefinedNullBooleanNumber String
  • 与其他语言不同, ECMScript 没有为整数和浮点数值分别定义不同的数据类型, Number 类型可用于表示所有数值。
  • ECMAScript 中也有一种复杂的数据类型,即 Object 类型,该类型是这门语言中所有对象的基础类型。
  • 严格模式为这门语言中容易出错的地方施加了限制。
  • ECMAScript 提供了很多与 C 及其他类 C 语言中相同的基本操作符,包括算术操作符、布尔操作符、关系操作符、相等操作符及赋值操作符等。
  • ECMAScript 从其他语言中借鉴了很多流控制语句,例如 if 语句、 for 语句和 switch 语句等。
ECMAScript 中的函数与其他语言中的函数有诸多不同之处。
        1、无须指定函数的返回值,因为任何 ECMAScript 函数都可以在任何时候返回任何值。
        2、实际上,未指定返回值的函数返回的是一个特殊的 undefined 值。
        3、ECMAScript 中也没有函数签名的概念,因为其函数参数是以一个包含零或多个值的数组的形式传递的。
        4、可以向 ECMAScript 函数传递任意数量的参数,并且可以通过 arguments 对象来访问这些参数。
        5、由于不存在函数签名的特性, ECMAScript 函数不能重载。 

你可能感兴趣的:(笔记,JavaScript,笔记)