天天看點

JavaScript 指南 - 使用對象使用對象

JavaScript 采用了簡單的基于對象的範型。一個對象就是一系列屬性的集合,一個屬性包含一個名字和一個值。一個屬性的值可以是函數,這種情況下屬性也被稱為方法。除了浏覽器裡面預定義的那些對象之外,你也可以定義你自己的對象。

本章描述了怎樣使用對象,屬性,函數和方法,以及怎樣建立你自己的對象。

javascript中的對象(物體),和其它程式設計語言中的對象一樣,可以比照現實生活中的對象(物體)來了解它。javascript中對象(物體)的概念可以比照着現實生活中實實在在的物體來了解他。

在javascript中,一個對象可以是一個單獨的擁有屬性和類型的實體。我們拿它和一個杯子做下類比。一個杯子是一個對象(物體),擁有屬性。杯子有顔色,圖案,重量,由什麼材質構成等等。同樣,javascript對象也有屬性來定義它的特征。

一個javascript對象有很多屬性。一個對象的屬性可以被解釋稱一個附加到對象上的一個變量。對象的屬性和普通的javascript變量基本沒什麼差別,僅僅是屬性屬于某個對象。屬性定義了對象的特征(譯注:動态語言面向對象的鴨子類型)。你可以通過點符号來通路一個對象的屬性。

和其他javascript變量一樣,對象的名字(可以是普通的變量)和屬性的名字都是大小寫敏感的。你可以在定義一個屬性的時候就給它指派。例如,我們建立一個myCar的對象然後給他三個屬性,make,model,year。具體如下所示:

JavaScript 對象的屬性也可以通過方括号通路. 對象有時也被叫作關聯數組, 因為每個屬性都有一個用于通路它的字元串值。例如,你可以按如下方式通路 myCar 對象的屬性:

一個對象的屬性名可以是任何有效的 JavaScript 字元串,,或者可以被轉換為字元串的任何東西,包括空字元串。然而,一個屬性的名稱如果不是一個有效的 JavaScript 辨別符(例如,一個有空格或短橫線,或者以數字開頭的屬性名),就隻能通過方括号标記通路。這個标記法在屬性名稱是動态判定(屬性名隻有到運作時才能判定)時非常有用。例如:

你也可以通過存儲在變量中的字元串來通路屬性:

因而,對于函數調用 <code>showProps(myCar, "myCar")</code> 将傳回以下值:

在 JavaScript 中,幾乎所有的東西都是對象。所有的原生類型除了 <code>null</code> 與 <code>undefined</code> 之外都被當作對象。它們可以被賦予屬性(某些類型的被賦予的屬性不能被持久化),并且它們都有對象的全部特征。

該方法依次通路一個對象及其原型鍊中所有可枚舉的屬性。

<a target="_blank" href="https://developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Global_Objects/Object/keys">Object.keys(o)</a>

該方法傳回一個對象 <code>o</code> 自身包含(不包括原型中)的所有屬性的名稱的數組。

<a target="_blank" href="https://developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames">Object.getOwnPropertyNames(o)</a>

該方法傳回一個數組,它包含了對象 <code>o</code> 所有擁有的屬性(無論是否可枚舉)的名稱。

在 ECMAScript 5 中,沒有原生的方法枚舉一個對象的所有屬性。然而,可以通過以下函數完成:

這在展示 “隐藏”(在原型中的不能通過對象通路的屬性,因為另一個同名的屬性存在于原型鍊的早期)的屬性時很有用。可以通過在數組中去除同名元素即可輕松地列出通路的屬性。

JavaScript 擁有一系列預定義的對象。另外,你可以建立你自己的對象。從  JavaScript 1.2 之後,你可以通過對象初始化器(Object Initializer)建立對象。或者你可以建立一個構造函數并使用該函數和 new 操作符初始化對象。

除了通過構造函數建立對象之外,你也可以通過對象初始化器建立對象。使用對象初始化器也被稱作通過字面值建立對象。對象初始化器與 C++ 術語相一緻。

通過對象初始化器建立對象的文法如下:

這裡 <code>obj</code> 是新對象的名稱,每一個 <code>property_i</code> 是一個辨別符(可以是一個名稱、數字或字元串字面量),并且每個 <code>value_i</code> 是一個其值将被賦予 property_i 的表達式。<code>obj</code> 與指派是可選的;如果你不需要在其他地方引用對象,你就不需要将它賦給一個變量。(注意在接受一條語句的地方,你可能需要将對象字面量括在括号裡,進而避免将字面量與塊語句相混淆)

如果一個對象是通過在頂級腳本的對象初始化器建立的,則 JavaScript 在每次遇到包含該對象字面量的表達式時都會建立對象。同樣的,在函數中的初始化器在每次函數調用時也會被建立。

下面的語句隻有當 <code>cond</code> 表達式的值為 <code>true</code> 時建立對象并将其賦給變量 <code>x</code>。

下例建立了有三個屬性的 <code>myHonda</code> 對象。注意它的 <code>engine</code> 屬性也是一個擁有自己屬性的對象。

作為另一種方式,你可以通過兩步來建立對象:

通過建立一個構造函數來定義對象的類型。首字母大寫是非常普遍而且很恰當的慣用法。

通過 <code>new 建立對象執行個體。</code>

為了定義對象類型,為對象類型建立一個函數以聲明類型的名稱、屬性和方法。例如,你想為汽車建立一個類型,并且将這類對象稱為 <code>car</code> ,并且擁有屬性 make, model, 和 year,你可以建立如下的函數:

注意通過使用 this 将傳入函數的值賦給對象的屬性。

現在你可以象這樣建立一個 <code>mycar</code> 對象:

該建立了 <code>mycar 并且将指定的值賦給它的屬性。因而 mycar.make 的值是字元串 "Eagle", mycar.year 的值是整數 1993,依此類推。</code>

你可以通過調用 <code>new</code> 建立任意數量的 <code>car </code>對象。例如:

一個對象的屬性值可以是另一個對象。例如,假設你按如下方式定義了 <code>person</code> 對象:

然後按如下方式建立了兩個 <code>person</code> 執行個體:

那麼,你可以重寫 <code>car</code> 的定義以包含一個擁有它的 <code>owner</code> 屬性,如:

你可以按如下方式建立新對象:

注意在建立新對象時,上面的語句将 <code>rand</code> 和 <code>ken</code> 作為 <code>owner</code> 的參數值,而不是傳入字元串字面量或整數值。接下來你如果想找出 car2 的擁有者的姓名,你可以通路如下屬性:

注意你總是可以為之前定義的對象增加新的屬性。例如,語句

為 <code>car1</code> 增加了 <code>color</code> 屬性,并将其值設為 "black." 然而,這并不影響其他的對象。想要為某個類型的所有對象增加新屬性,你必須将屬性加入到 <code>car </code>對象類型的定義中。

所有的 JavaScript 對象繼承于至少一個對象。被繼承的對象被稱作原型,并且繼承的屬性可能通過構造函數的 <code>prototype</code> 對象找到。

在 JavaScript 1.0 中,你可以通過名稱或序号通路一個屬性。但是在 JavaScript 1.1 及之後版本中,如果你最初使用名稱定義了一個屬性,則你必須通過名稱來通路它;而如果你最初使用序号來定義一個屬性,則你必須通過索引來通路它。

這個限制發生在你通過構造函數建立一個對象和它的屬性(就象我們之前通過 <code>Car</code> 對象類型所做的那樣)并且顯式地定義了單獨的屬性(如 myCar.color = "red")之時。如果你最初使用索引定義了一個對象屬性,例如 <code>myCar[5] = "25"</code>,則你之可隻能通過 <code>myCar[5]</code> 引用它。

這條規則的例外是從與HTML對應的對象,例如 <code>forms</code> 數組。對于這些數組的元素,你總是既可以通過其序号(依據其在文檔中出現的順序),也可以按照其名稱(如果有的話)通路它。舉例而言,如果文檔中的第二個 <code>&lt;form&gt;</code> 标簽有一個 <code>NAME</code> 屬性且值為<code> "myForm",通路該 form 的方式可以是 document.forms[1],document.forms["myForm"]或 document.myForm。</code>

為對象類型定義屬性

你可以通過 <code>prototype </code>屬性為之前定義的對象類型增加屬性。這為該類型的所有對象,而不是僅僅一個對象增加了一個屬性。下面的代碼為所有類型為<code>car </code>的對象增加了 <code>color</code> 屬性,然後為對象 <code>car1</code> 的 <code>color</code> 屬性指派:

一個方法是關聯到某個對象的函數,或者簡單地說,一個方法是一個值為某個函數的對象屬性。定義方法就象定義普通的函數,除了它們必須被賦給對象的某個屬性。例如:

這裡 <code>objectName</code> 是一個已經存在的函數,<code>methodname</code> 是方法的名稱,而 <code>function_name</code> 是函數的名稱。

你可以在對象的上下文中象這樣調用方法:

你可以在對象的構造函數中包含方法定義來為某個對象類型定義方法。例如,你可以為之前定義的 car 對象定義一個函數格式化并顯示其屬性:

這裡 <code>pretty_print</code> 是一個顯示橫線和一個字元串的函數。注意使用 this 指代方法所屬的對象。

你可以在對象定義中通過增加下述語句将這個函數變成 <code>car</code> 的方法:

是以,<code>car</code> 的完整定義看上去将是:

然後你可以按如下方式為每個對象調用 <code>displayCar</code> 方法:

這樣導緻如下圖所示的輸出結果:

JavaScript 指南 - 使用對象使用對象

Figure 7.1: Displaying method output.

JavaScript 有一個特殊的關鍵字 <code>this</code>,它可以在方法中使用以指代目前對象。例如,假設你有一個名為 <code>validate</code> 的函數,它根據給出的最大與最小值檢查某個對象的 <code>value</code> 屬性:

然後,你可以在每個元素的 <code>onchange</code> 事件處理器中調用 <code>validate</code>,并通過 <code>this</code> 傳入相應元素,代碼如下:

總的說來, <code>this</code> 在一個方法中指調用的對象。

當與 <code>form</code> 屬性一起使用時,<code>this </code>可以指代目前對象的父窗體。在下面的例子中,窗體 <code>myForm</code> 包含一個 <code>Text </code>對象和一個按鈕,當使用者點選按鍵,<code>Text</code>對象的值被設為窗體的名稱。按鈕的 <code>onclick</code> 事件處理器使用 <code>this.form</code> 以指代其父窗體,即 <code>myForm</code>。

一個 getter 是一個擷取某個特定屬性的值的方法。一個 setter 是一個設定某個屬性的值的方法。你可以為預定義的或使用者定義的對象定義 getter 和 setter 以支援新增的屬性。定義 getter 和 setter 的文法采用對象字面量文法。

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

The <code>o</code> object's properties are:

<code>o.a</code> — a number

<code>o.b</code> — a getter that returns <code>o.a</code> plus 1

<code>o.c</code> — a setter that sets the value of <code>o.a</code> to half of the value <code>o.c</code> is being set to

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

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

These statements use the getter and setter in a <code>Date</code> object:

In principle, getters and setters can be either

added later to any object at any time using a getter or setter adding method.

Getters and setters can also be added to an object at any time after creation using two special methods called <code>__defineGetter__</code> and<code>__defineSetter__</code>. 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):

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 <code>(HTMLElement.prototype.__define[SG]etter__)</code> 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.

你可以用 <code>delete</code> 操作符删除一個不是繼承而來的屬性。下面的例子說明如何删除一個屬性:

如果一個全局變量不是用 <code>var</code> 關鍵字聲明的話,你也可以用 <code>delete</code> 删除它:

<a target="_blank" href="http://es5.github.com/#x4.2">ECMAScript 5.1 spec: Language Overview</a>

<a target="_blank" href="http://dmitrysoshnikov.com/ecmascript/javascript-the-core">JavaScript. The core. (Dmitry A. Soshnikov ECMA-262 article series)</a>

檔案

大小

日期

附加者為

<a target="_blank" href="https://mdn.mozillademos.org/files/579/obja.gif">obja.gif</a>

3284 位元組

2005-04-22 08:49:02

<a target="_blank" href="https://developer.mozilla.org/zh-CN/profiles/JdeValk">JdeValk</a>

<a target="_blank" href="https://mdn.mozillademos.org/files/786/understanding-underlines-figure06.gif">understanding-underlines-figure06.gif</a>

2038 位元組

2005-05-02 06:15:07

<a target="_blank" href="https://developer.mozilla.org/zh-CN/profiles/CitizenK">CitizenK</a>

繼續閱讀