mozilla
您的搜索结果

    使用对象

    JavaScript 采用了简单的基于对象的范型。一个对象就是一系列属性的集合,一个属性包含一个名字和一个值。一个属性的值可以是函数,这种情况下属性也被称为方法。除了浏览器里面预定义的那些对象之外,你也可以定义你自己的对象。

    本章描述了怎样使用对象,属性,函数和方法,以及怎样创建你自己的对象。

    对象综述

    javascript 中的对象(物体),和其它编程语言中的对象一样,可以比照现实生活中的对象(物体)来理解它。 javascript 中对象(物体)的概念可以比照着现实生活中实实在在的物体来理解。

    在javascript中,一个对象可以是一个单独的拥有属性和类型的实体。我们拿它和一个杯子做下类比。一个杯子是一个对象(物体),拥有属性。杯子有颜色,图案,重量,由什么材质构成等等。同样,javascript对象也有属性来定义它的特征。

    对象和属性

    一个 javascript 对象有很多属性。一个对象的属性可以被解释成一个附加到对象上的变量。对象的属性和普通的 javascript 变量基本没什么区别,仅仅是属性属于某个对象。属性定义了对象的特征(译注:动态语言面向对象的鸭子类型)。你可以通过点符号来访问一个对象的属性。

    objectName.propertyName
    

    和其他 javascript 变量一样,对象的名字(可以是普通的变量)和属性的名字都是大小写敏感的。你可以在定义一个属性的时候就给它赋值。例如,我们创建一个myCar的对象然后给他三个属性,make,model,year。具体如下所示:

    var myCar = new Object();
    myCar.make = "Ford";
    myCar.model = "Mustang";
    myCar.year = 1969; 

    JavaScript 对象的属性也可以通过方括号访问. 对象有时也被叫作关联数组, 因为每个属性都有一个用于访问它的字符串值。例如,你可以按如下方式访问 myCar 对象的属性:

    myCar["make"] = "Ford";
    myCar["model"] = "Mustang";
    myCar["year"] = 1969;
    

    一个对象的属性名可以是任何有效的 JavaScript 字符串,,或者可以被转换为字符串的任何东西,包括空字符串。然而,一个属性的名称如果不是一个有效的 JavaScript 标识符(例如,一个有空格或短横线,或者以数字开头的属性名),就只能通过方括号标记访问。这个标记法在属性名称是动态判定(属性名只有到运行时才能判定)时非常有用。例如:

    var myObj = new Object(),
        str = "myString",
        rand = Math.random(),
        obj = new Object();
    
    myObj.type              = "Dot syntax";
    myObj["date created"]   = "String with space";
    myObj[str]              = "String value";
    myObj[rand]             = "Random Number";
    myObj[obj]              = "Object";
    myObj[""]               = "Even an empty string";
    
    console.log(myObj);
    

    你也可以通过存储在变量中的字符串来访问属性:

    var propertyName = "make";
    myCar[propertyName] = "Ford";
    
    propertyName = "model";
    myCar[propertyName] = "Mustang";
    

    你可以在  for...in 语句中使用方括号标记以枚举一个对象的所有属性。为了展示它如何工作,下面的函数当你将对象及其名称作为参数传入时,显示对象的属性:

    function showProps(obj, objName) {
      var result = "";
      for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
            result += objName + "." + i + " = " + obj[i] + "\n";
        }
      }
      return result;
    }
    

    因而,对于函数调用 showProps(myCar, "myCar") 将返回以下值:

    myCar.make = Ford
    myCar.model = Mustang
    myCar.year = 1969

    对象即全部

    在 JavaScript 中,几乎所有的东西都是对象。所有的原生类型除了 nullundefined 之外都被当作对象。它们可以被赋予属性(某些类型的被赋予的属性不能被持久化),并且它们都有对象的全部特征。

    枚举一个对象的所有属性

    从 ECMAScript 5 开始,有三种原生的方法用于列出或枚举对象的属性:

    • for...in 循环
      该方法依次访问一个对象及其原型链中所有可枚举的属性。
    • Object.keys(o)
      该方法返回一个对象 o 自身包含(不包括原型中)的所有属性的名称的数组。
    • Object.getOwnPropertyNames(o)
      该方法返回一个数组,它包含了对象 o 所有拥有的属性(无论是否可枚举)的名称。

    在 ECMAScript 5 中,没有原生的方法枚举一个对象的所有属性。然而,可以通过以下函数完成:

    function listAllProperties(o){     
    	var objectToInspect;     
    	var result = [];
    	
    	for(objectToInspect = o; objectToInspect !== null; objectToInspect = Object.getPrototypeOf(objectToInspect)){  
    		result = result.concat(Object.getOwnPropertyNames(objectToInspect));  
    	}
    	
    	return result; 
    }
    

    这在展示 “隐藏”(在原型中的不能通过对象访问的属性,因为另一个同名的属性存在于原型链的早期)的属性时很有用。可以通过在数组中去除同名元素即可轻松地列出访问的属性。

    创建新对象

    JavaScript 拥有一系列预定义的对象。另外,你可以创建你自己的对象。从  JavaScript 1.2 之后,你可以通过对象初始化器(Object Initializer)创建对象。或者你可以创建一个构造函数并使用该函数和 new 操作符初始化对象。

    使用对象初始化器

    除了通过构造函数创建对象之外,你也可以通过对象初始化器创建对象。使用对象初始化器也被称作通过字面值创建对象。对象初始化器与 C++ 术语相一致。

    通过对象初始化器创建对象的语法如下:

    var obj = { property_1:   value_1,   // property_# may be an identifier...
                2:            value_2,   // or a number...
                // ...,
                "property n": value_n }; // or a string
    

    这里 obj 是新对象的名称,每一个 property_i 是一个标识符(可以是一个名称、数字或字符串字面量),并且每个 value_i 是一个其值将被赋予 property_i 的表达式。obj 与赋值是可选的;如果你不需要在其他地方引用对象,你就不需要将它赋给一个变量。(注意在接受一条语句的地方,你可能需要将对象字面量括在括号里,从而避免将字面量与块语句相混淆)

    如果一个对象是通过在顶级脚本的对象初始化器创建的,则 JavaScript 在每次遇到包含该对象字面量的表达式时都会创建对象。同样的,在函数中的初始化器在每次函数调用时也会被创建。

    下面的语句只有当 cond 表达式的值为 true 时创建对象并将其赋给变量 x

    if (cond) var x = {hi: "there"};
    

    下例创建了有三个属性的 myHonda 对象。注意它的 engine 属性也是一个拥有自己属性的对象。

    var myHonda = {color: "red", wheels: 4, engine: {cylinders: 4, size: 2.2}};
    

    你也可以用对象初始化器来创建数组。参见 array literals.

    在 JavaScript 1.1 及更早版本中,你不能使用对象初始化器。你只能通过使用构造函数或其他对象的函数来创建对象。参见 Using a constructor function.

    使用构造函数

    作为另一种方式,你可以通过两步来创建对象:

    1. 通过创建一个构造函数来定义对象的类型。首字母大写是非常普遍而且很恰当的惯用法。
    2. 通过 new 创建对象实例。

    为了定义对象类型,为对象类型创建一个函数以声明类型的名称、属性和方法。例如,你想为汽车创建一个类型,并且将这类对象称为 car ,并且拥有属性 make, model, 和 year,你可以创建如下的函数:

    function Car(make, model, year) {
      this.make = make;
      this.model = model;
      this.year = year;
    }
    

    注意通过使用 this 将传入函数的值赋给对象的属性。

    现在你可以象这样创建一个 mycar 对象:

    var mycar = new Car("Eagle", "Talon TSi", 1993);
    

    该创建了 mycar 并且将指定的值赋给它的属性。因而 mycar.make 的值是字符串 "Eagle", mycar.year 的值是整数 1993,依此类推。

    你可以通过调用 new 创建任意数量的 car 对象。例如:

    var kenscar = new Car("Nissan", "300ZX", 1992);
    var vpgscar = new Car("Mazda", "Miata", 1990);
    

    一个对象的属性值可以是另一个对象。例如,假设你按如下方式定义了 person 对象:

    function Person(name, age, sex) {
      this.name = name;
      this.age = age;
      this.sex = sex;
    }
    

    然后按如下方式创建了两个 person 实例:

    var rand = new Person("Rand McKinnon", 33, "M");
    var ken = new Person("Ken Jones", 39, "M");
    

    那么,你可以重写 car 的定义以包含一个拥有它的 owner 属性,如:

    function Car(make, model, year, owner) {
      this.make = make;
      this.model = model;
      this.year = year;
      this.owner = owner;
    }
    

    你可以按如下方式创建新对象:

    var car1 = new Car("Eagle", "Talon TSi", 1993, rand);
    var car2 = new Car("Nissan", "300ZX", 1992, ken);
    

    注意在创建新对象时,上面的语句将 randken 作为 owner 的参数值,而不是传入字符串字面量或整数值。接下来你如果想找出 car2 的拥有者的姓名,你可以访问如下属性:

    car2.owner.name
    

    注意你总是可以为之前定义的对象增加新的属性。例如,语句

    car1.color = "black";
    

    car1 增加了 color 属性,并将其值设为 "black." 然而,这并不影响其他的对象。想要为某个类型的所有对象增加新属性,你必须将属性加入到 car 对象类型的定义中。

    使用 Object.create 方法

    对象也可以用 Object.create 方法创建。该方法非常有用,因为它允许你为创建的对象选择其原型对象,而不用定义一个构造函数。该函数更多的信息及详细用法,参见 Object.create method

    继承

    所有的 JavaScript 对象继承于至少一个对象。被继承的对象被称作原型,并且继承的属性可能通过构造函数的 prototype 对象找到。

    对象属性索引

    在 JavaScript 1.0 中,你可以通过名称或序号访问一个属性。但是在 JavaScript 1.1 及之后版本中,如果你最初使用名称定义了一个属性,则你必须通过名称来访问它;而如果你最初使用序号来定义一个属性,则你必须通过索引来访问它。

    这个限制发生在你通过构造函数创建一个对象和它的属性(就象我们之前通过 Car 对象类型所做的那样)并且显式地定义了单独的属性(如 myCar.color = "red")之时。如果你最初使用索引定义了一个对象属性,例如 myCar[5] = "25",则你之可只能通过 myCar[5] 引用它。

    这条规则的例外是从与HTML对应的对象,例如 forms 数组。对于这些数组的元素,你总是既可以通过其序号(依据其在文档中出现的顺序),也可以按照其名称(如果有的话)访问它。举例而言,如果文档中的第二个 <form> 标签有一个 NAME 属性且值为 "myForm",访问该 form 的方式可以是 document.forms[1],document.forms["myForm"]或 document.myForm。

    为对象类型定义属性

    你可以通过 prototype 属性为之前定义的对象类型增加属性。这为该类型的所有对象,而不是仅仅一个对象增加了一个属性。下面的代码为所有类型为 car 的对象增加了 color 属性,然后为对象 car1color 属性赋值:

    Car.prototype.color = null;
    car1.color = "black";
    

    参见 JavaScript Reference 中 Function 对象的 prototype 属性 。

    定义方法

    一个方法 是关联到某个对象的函数,或者简单地说,一个方法是一个值为某个函数的对象属性。定义方法就象定义普通的函数,除了它们必须被赋给对象的某个属性。例如:

    objectName.methodname = function_name;
    
    var myObj = {
      myMethod: function(params) {
        // ...do something
      }
    };
    

    这里 objectName 是一个已经存在的函数,methodname 是方法的名称,而 function_name 是函数的名称。

    你可以在对象的上下文中象这样调用方法:

    object.methodname(params);
    

    你可以在对象的构造函数中包含方法定义来为某个对象类型定义方法。例如,你可以为之前定义的 car 对象定义一个函数格式化并显示其属性:

    function displayCar() {
      var result = "A Beautiful " + this.year + " " + this.make
        + " " + this.model;
      pretty_print(result);
    }
    

    这里 pretty_print 是一个显示横线和一个字符串的函数。注意使用 this 指代方法所属的对象。

    你可以在对象定义中通过增加下述语句将这个函数变成 car 的方法:

    this.displayCar = displayCar;
    

    因此,car 的完整定义看上去将是:

    function Car(make, model, year, owner) {
      this.make = make;
      this.model = model;
      this.year = year;
      this.owner = owner;
      this.displayCar = displayCar;
    }
    

    然后你可以按如下方式为每个对象调用 displayCar 方法:

    car1.displayCar();
    car2.displayCar();
    

    这样导致如下图所示的输出结果:

    Image:obja.gif

    Figure 7.1: Displaying method output.

    通过 this 引用对象

    JavaScript 有一个特殊的关键字 this,它可以在方法中使用以指代当前对象。例如,假设你有一个名为 validate 的函数,它根据给出的最大与最小值检查某个对象的 value 属性:

    function validate(obj, lowval, hival) {
      if ((obj.value < lowval) || (obj.value > hival))
        alert("Invalid Value!");
    }
    

    然后,你可以在每个元素的 onchange 事件处理器中调用 validate,并通过 this 传入相应元素,代码如下:

    <input type="text" name="age" size="3"
      onChange="validate(this, 18, 99)">
    

    总的说来, this 在一个方法中指调用的对象。

    当与 form 属性一起使用时,this 可以指代当前对象的父窗体。在下面的例子中,窗体 myForm 包含一个 Text 对象和一个按钮,当用户点击按键,Text 对象的值被设为窗体的名称。按钮的 onclick 事件处理器使用 this.form 以指代其父窗体,即 myForm

    <form name="myForm">
    <p><label>Form name:<input type="text" name="text1" value="Beluga"></label>
    <p><input name="button1" type="button" value="Show Form Name"
         onclick="this.form.text1.value = this.form.name">
    </p>
    </form>

    定义 getter 与 setter

    一个 getter 是一个获取某个特定属性的值的方法。一个 setter 是一个设定某个属性的值的方法。你可以为预定义的或用户定义的对象定义 getter 和 setter 以支持新增的属性。定义 getter 和 setter 的语法采用对象字面量语法。

    JavaScript 1.8.1 note

    Starting in JavaScript 1.8.1, setters are no longer called when setting properties in object and array initializers.

    下面的  JS shell 语句描述了getters 和 setters 是如何为用户定义的对象 o 工作的。 JS shell 是一个应用程序,允许开发者以批处理或交互的方法测试 JavaScript。在 Firefox 中,你可以通过Ctrl+Shift+K 组合按键调用 JS shell。

    js> var o = {a: 7, get b() {return this.a + 1;}, set c(x) {this.a = x / 2}};
    [object Object]
    js> o.a;
    7
    js> o.b;
    8
    js> o.c = 50;
    js> o.a;
    25
    

    o 对象的属性如下:

    • o.a — 数字
    • o.b — 返回 o.a + 1 的 getter
    • o.c — 由  o.c 的值所设置 o.a 值的 setter

    Please note that function names of getters and setters defined in an object literal using "[gs]et property()" (as opposed to __define[GS]etter__ below) are not the names of the getters themselves, even though the [gs]et propertyName(){ } syntax may mislead you to think otherwise. To name a function in a getter or setter using the "[gs]et property()" syntax, define an explicitly named function programmatically using Object.defineProperty (or the Object.prototype.__defineGetter__ legacy fallback).

    This JavaScript shell session illustrates how getters and setters can extend the Date prototype to add a year property to all instances of the predefined Date class. It uses the Date class's existing getFullYear and setFullYear methods to support the year property's getter and setter.

    These statements define a getter and setter for the year property:

    js> var d = Date.prototype;
    js> d.__defineGetter__("year", function() { return this.getFullYear(); });
    js> d.__defineSetter__("year", function(y) { this.setFullYear(y); });
    

    These statements use the getter and setter in a Date object:

    js> var now = new Date;
    js> print(now.year);
    2000
    js> now.year = 2001;
    987617605170
    js> print(now);
    Wed Apr 18 11:13:25 GMT-0700 (Pacific Daylight Time) 2001
    

    Obsolete syntaxes

    In the past, JavaScript supported several other syntaxes for defining getters and setters. None of these syntaxes were supported by other engines, and support has been removed in recent versions of JavaScript. See this dissection of the removed syntaxes for further details on what was removed and how to adapt to those removals.

    小结

    In principle, getters and setters can be either

    • defined using object initializers, or
    • added later to any object at any time using a getter or setter adding method.

    When defining getters and setters using object initializers all you need to do is to prefix a getter method with get and a setter method with set. Of course, the getter method must not expect a parameter, while the setter method expects exactly one parameter (the new value to set). For instance:

    var o = {
      a: 7,
      get b() { return this.a + 1; },
      set c(x) { this.a = x / 2; }
    };
    

    Getters and setters can also be added to an object at any time after creation using two special methods called __defineGetter__ and __defineSetter__. Both methods expect the name of the getter or setter as their first parameter, in the form of a string. The second parameter is the function to call as the getter or setter. For instance (following the previous example):

    o.__defineGetter__("b", function() { return this.a + 1; });
    o.__defineSetter__("c", function(x) { this.a = x / 2; });
    

    Which of the two forms to choose depends on your programming style and task at hand. If you already go for the object initializer when defining a prototype you will probably most of the time choose the first form. This form is more compact and natural. However, if you need to add getters and setters later — because you did not write the prototype or particular object — then the second form is the only possible form. The second form probably best represents the dynamic nature of JavaScript — but it can make the code hard to read and understand.

    Prior to Firefox 3.0, getter and setter are not supported for DOM Elements. Older versions of Firefox silently fail. If exceptions are needed for those, changing the prototype of HTMLElement (HTMLElement.prototype.__define[SG]etter__) and throwing an exception is a workaround.

    With Firefox 3.0, defining getter or setter on an already-defined property will throw an exception. The property must be deleted beforehand, which is not the case for older versions of Firefox.

    See also

    删除属性

    你可以用 delete 操作符删除一个不是继承而来的属性。下面的例子说明如何删除一个属性:

    //Creates a new object, myobj, with two properties, a and b.
    var myobj = new Object;
    myobj.a = 5;
    myobj.b = 12;
    
    //Removes the a property, leaving myobj with only the b property.
    delete myobj.a;
    

    如果一个全局变量不是用 var 关键字声明的话,你也可以用 delete 删除它:

    g = 17;
    delete g;
    

    参见delete 以获取更多信息。

    比较对象

    在 JavaScript 中 objects 是一个引用类型。将两个引用相同的对象想比较会返回 true; 将两个方法和属性相同的对象相比较,会返回 false;

    // fruit object reference variable
    var fruit = {name: "apple"};
    
    // fruitbear object reference variable
    var fruitbear = {name: "apple"};
    
    fruit == fruitbear // return false
    
    fruit === fruitbear // return false

    注意: "===" 运算符用来检查数值是否相等: 1 === "1" // return false and 1 == "1" // return true

    // fruit object reference variable
    var fruit = {name: "apple"};
    
    // fruitbear object reference variable
    var fruitbear = fruit;  // assign fruit object reference to fruitbear object reference variable
    
    // here fruit and fruitbear pointing to same object called fruit
    fruit == fruitbear // return true
    
    // here fruit and fruitbear pointing to same object called fruit
    fruit === fruitbear // return true

    See also

    文档标签和贡献者

    此页面的贡献者有: ziyunfei, koala, ReyCG_sub, smartkid, teoli
    最后编辑者: ReyCG_sub,