JavaScript 网页编程从入门到精通 (清华社"视频大讲堂"大系·网络开发视频大讲堂)
上QQ阅读APP看书,第一时间看更新

5.7 对象操作运算符

对象操作运算符主要是指对对象、数组、函数执行特定任务操作的一组运算符,主要包括in、instanceof、new、delete、.(点号)、[](中括号)和()(小括号)运算符。

5.7.1 new运算符

new运算符可以根据构造函数创建一个新的对象,并初始化该对象。其语法如下:

      new constructor( arguments)

constructor必须是一个构造函数表达式,其后面应该是利用小括号包含的参数列表,参数可有可无,参数之间通过逗号进行分隔。如果函数调用时没有参数,可以省略小括号。

【示例1】下面的代码使用了new运算符实例化Array,并演示了3种不同的使用方法。

      var a=new Array;                             //创建数组结构的对象,省略了小括号
      var b=new Array();                           //创建数组结构的对象
      var c=new Array(1,2,3);                      //创建数组结构的对象,并初始化它的数据
      alert(c[2]);                                 //返回值3。读取并显示新创建数组对象中的元素值

new运算符被执行时,首先会创建一个新对象,接着new运算符调用指定的构造函数(类),这里是Array数组构造函数,并根据是否指定参数来初始化构造函数,利用这个初始化的构造函数结构和数据(如果传递参数的话)初始化新对象。

【示例2】下面代码使用自定义类创建新的对象。

      var a=function(){                           //自定义类a的数据结构
          this.x=1;                               //类成员x
          this.y=2;                               //类成员y
      };
      var b=new a;                                //创建自定义类a的对象实例
      alert(b.x);                                 //返回1,调用对象的成员

对于自定义类来说,只能够通过new运算符来进行实例化。

【示例3】下面方法将返回undefined。因为虽然把类的数据结构赋值给变量b,但是由于没有实例化,所以无法访问。

      var a=function(){                            //自定义类a的数据结构
          this.x=1;                                //定义类成员x
          this.y=2;                                //定义类成员y
      };
      var b=  a;                                   //通过赋值运算符克隆自定义类的数据结构
      alert(b.x);                                  //返回undefined

【示例4】对于下面这个对象结构来说,则可以使用赋值运算符进行快速引用:

      var a={                                   //自定义对象a数据结构
        x:1,                                    //定义对象成员
        y:2                                     //定义对象成员
      };
      var b=a;                                  //直接克隆对象数据结构
      alert(b.x);                               //返回1,调用对象的成员

5.7.2 delete运算符

delete运算符能够删除指定对象的属性、数组元素或变量。

【示例1】下面的代码使用了delete运算符删除对象a的属性x。

      var a={                                   //定义对象a
        x:1,                                    //定义对象成员
        y:2                                     //定义对象成员
      };
      alert(a.x);                               //返回1,调用对象成员
      delete a.x;                               //删除对象成员x
      alert(a.x);                               //返回undefined,没有找到该对象成员

执行delete运算时,如果删除操作成功,将返回true;如果不能够被删除,则返回false。

      var a={                                         //定义对象a
        x : 1,
        y : 2
      };
      alert(delete a.x);                              //返回true,说明删除成功

【示例2】不是所有对象成员或变量都可以被删除的,如某些内置对象的预定义成员和客户端对象成员,使用var语句声明的变量也是不允许删除的。

      a=1;                                     //初始化变量a,没有使用var语句声明
      alert(delete a);                         //返回true,说明删除成功
      var b=1;                                 //使用var语句声明并初始化变量
      alert(delete b);                         //返回false,说明不允许删除
      alert(delete Object.constructor);
                                               //返回true,说明部分内部成员可以被删除
      alert(delete Object.valueOf());
                                               //返回错误,说明某些内部成员不可以被删除

【示例3】如果删除不存在的对象成员,或者非对象成员、数组元素、变量时,它会返回true,所以使用delete运算符时,应该注意这个问题,防止与成功删除操作相混淆。

      var a={                                        //定义对象a
        x : 1,
        y : 2
      };
      alert(delete a);                               //返回false,说明不允许删除
      alert(delete a.z);                             //返回true,说明不存在该属性
      alert(delete Object);                          //返回true,说明删除的不是成员、元素或变量
      alert(delete b);                               //返回true,说明不存在该变量

提示:使用delete运算符应该注意几个问题:

第一,delete运算符只能删除值类型的数据。不影响变量、属性或数组元素存储的原引用对象。例如:

              var a={                              //定义对象a
                x : 1
              };
              var b={                              //定义对象b
                y : a
              };
              alert(delete(b.y));                  //删除对象b中y属性对对象a的引用
              alert(a.x);                          //返回1。但是原引用对象a并没有被删除

第二,delete运算符的删除操作不是清空值,即把变量、属性或数组元素的值设置为undefined,而是彻底删除它们占用的存储空间。在JavaScript 1.1和JavaScript 1.0版本中仅是把变量、属性或数组元素设置为null。

第三,除了使用delete运算符手动清除不用的内存外,JavaScript主要是利用内置的一个垃圾回收程序来自动对系统进行清理,所以并不需要手动调用delete运算符来释放对象所占用的空间。

第四,灵活使用delete运算符,配合in运算符,可以很方便地操作对象成员、数组元素等,如检测、插入、删除或更新操作。

              var a=[];                            //定义空数组a
              if("x"in a)                          //如果数组a中存在元素x
                  delete a["x"];                   //则删除元素x
              else                                 //如果不存在元素x
                  a["x"]=true;                     //则插入数组元素x,并为其赋值true
              alert(a.x);                          //返回true。查看数组元素x的值
              if(delete a["x"])                    //如果删除数组元素x成功
                  a["x"]=false;                    //更新数组元素x的值为false
              alert(a.x);                          //返回false。查看数组元素x的值

5.7.3 中括号和点号运算符

中括号和点号都属于存取运算符,用于访问对象或数组。使用中括号运算符([])可以存取数组元素值,使用点号运算符(.)可以存取对象属性值。用法如下:

      a.b                                       //点运算符的用法
      c[d]                                      //中括号运算符的用法

在上面代码中,运算数a表示对象,运算数b表示一个标识符,如属性名。如果属性值是函数,应在标识名后面增加小括号运算符,实现方法调用操作。注意,运算数b是不能使用字符串,也不能够使用值为字符串的表达式。

运算数c可以是数组,也可以是对象。如果左侧运算数是数组,则中括号包含的运算数应是一个值为正整数的表达式(下标值)。如果左侧运算数是对象,则中括号包含的运算数应是一个值为字符串的表达式,它与对象属性名的字符串对应。

【示例1】中括号运算符([])不仅可以存取数组元素的值,还可以存取对象属性值。

读取数组元素的值

      var a=[1, "x", true, {}];                     //定义数组a
      alert(a[1]);                                  //返回"x"。读取数组中第2个元素的值
      alert(a[3]);                                  //返回[object Object]。读取数组中第4个元素的值

对于数组来说,可以通过数组下标来指定元素在数组中的位置,起始位置为0。

写入数组元素的值

      var a=[1, "x", true, {}];                     //定义数组a
      a[3]=false;                                   //在数组第4个元素中写入false布尔值
      alert(a[3]);                                  //返回false。元素原来存储的对象被覆盖

读取对象属性值

      var a={                                   //定义对象a
        x:1,                                    //定义对象属性x
        y: function(){                          //定义对象方法y
          return 2;                             //返回值2
        }
      };
      alert(a["x"]);                            //返回1。读取属性x的值
      alert(a["y"]());                          //返回2。调用方法y

对于对象来说,可以通过对象属性名称字符串来指定成员在对象中的位置。

重置对象属性值

      var a={                                   //定义对象a
        x:1,                                    //定义对象属性x
        y: function(){                          //定义对象方法y
          return 2;                             //返回值2
        }
      };
      a["x"]=3;                                 //重置属性x的值
      alert(a["x"]);                            //返回3。读取属性x的值
      a["y"]=function(){                        //更新方法y
          return 4;
      }
      alert(a["y"]());                          //返回4。调用方法y

【示例2】点号运算符(.)可以存取对象属性值,它比中括号灵活、方便,因为点号运算符右侧可以直接指定属性的标识符,而不是属性名称的字符串或变量。

      var a={                                   //定义对象a
        x : 1,
      };
      alert(a.x);                               //返回1。读取对象属性a的值
      a.x=2;                                    //重写对象属性a的值
      alert(a.x);                               //返回2。再次读取对象属性a的值

对于中括号运算符可以通过变量或字符串表达式来传递特定值。

      var b="x";                               //把属性x的标识符名作为字符串存储在变量b中
      var a={                                  //定义对象a
        x:1                                    //定义属性x
      };
      alert(a[b]);                             //返回1。通过变量间接获取对象a的属性x的值
      alert(a.b);                              //返回undefined。点运算符无法识别这种变量引用法

中括号运算符能够对第二个运算数执行运算,并对返回值的类型进行转换。这种类型转换与关系运算符的类型转换规则类似。

【示例3】对于下面两种方法都可以读取数组a中第二个元素的值。虽然说a["1"]中参数是一个字符串,但是中括号运算符能够把它转换为数字。

      var a=["x", true, {}];                   //定义数组
      alert(a[1]);                             //返回true
      alert(a["1"]);                           //返回true

与关系运算符不同,如果中括号运算符中第二个运算数为对象时,会使用toString()方法进行转换,如果失败,则会调用valueOf()方法转换。同时对于布尔值true和false将被转换为字符串"true"和"false",而不是1和0。

      var a={                               //定义对象
          "true":1,
          //定义属性"true"。为了避免与系统标识符冲突,这里加了引号,以表示它是一个字符串
          "false":0
          //定义属性"false"。为了避免与系统标识符冲突,这里加了引号,以表示它是一个字符串
      }
      alert(a[true]);    //返回1。此时中括号运算符会先把布尔值true转换为字符串"true",而不是数值1
      alert(a[false]);   //返回0。此时中括号运算符会先把布尔值false转换为字符串"false",而不是数值0

当对象被用作关联数组时,由于对象的属性名是动态生成的,所以不能够使用点号运算符来准确操作对象属性。但是如果使用中括号运算符来操作对象属性时,反而更方便,借助for循环语句可以实现自动化读写操作。

【示例4】下面代码能够遍历客户端window对象的所有属性以及属性值。这里主要使用了中括号运算符来操作document对象的属性,这种批量读取属性及其值的操作,如果使用点号运算符来实现是非常困难的,甚至是不可能的。

      for(o in window){                        //遍历window对象成员,此时对象被看作关联数组
        document.write("window." + o + " = " + window[o] + "<br />");
      }

如果点号运算符右侧的标识符不存在,在读取该成员时返回undefined值,而不是返回错误。例如:

      var a={                                  //定义对象
          x:1                                  //定义属性
      }
      alert(a.y);                              //返回undefined。读取不出来的成员

如果点号运算符右侧的标识符不存在,而为该标识符写入值时,会创建新的对象成员。例如:

      var a={                               //定义对象
          x:1                               //定义属性
      }
      alert(a.y);                           //返回undefined。说明不存在该成员
      a.y=2;                                //新建属性,并写入值
      alert(a.y);                           //返回2。说明存在该属性,且值为2
      a.y=function(){                       //重写该成员,设置该成员为一个方法,返回值为3
        return 3;
      };
      alert(a.y());                         //返回3。再次调用该方法

5.7.4 小括号运算符

小括号是一个特殊的运算符,它没有固定数目的运算数。其中第一个运算数必须是一个函数名或者引用函数的表达式,其后附加小括号运算符,小括号中可以包含数量没有限制的运算数,它们之间通过逗号进行分隔。语法如下:

      f (a, b, c……)

其中运算数f是一个函数名或者引用函数的表达式,a、b、c……是数目不详的参数,这些参数可以是任意类型的表达式。

【示例】下面的代码演示了如何使用小括号运算符调用函数的过程。

      function a(){                            //定义函数a
          alert("Hello, World");               //函数体包含的语句
      }
      a;                                       //直接引用函数名,没有反应
      a();                                     //返回提示信息"Hello, World"。没有传递参数,直接调用
      a(1, "string", {}, true);                //返回提示信息"Hello, World"。传递4个不同类型的参数

小括号运算符在执行时是这样的:先对每个运算数进行计算,然后调用第一个运算数所指的函数,同时把余下的运算数的值传递给函数作为它的参数。