aboutsummaryrefslogtreecommitdiff
path: root/files/zh-tw/learn/javascript/objects/basics/index.html
blob: 3b705366566f70a626a21d3b1c39261d99c51522 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
---
title: JavaScript 物件基礎概念
slug: Learn/JavaScript/Objects/Basics
translation_of: Learn/JavaScript/Objects/Basics
---
<div>{{LearnSidebar}}</div>

<div>{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}</div>

<p class="summary">第一篇談到 JavaScript 物件的文章中,我們了解到基本的 JavaScript 物件語法,複習了某些先前提過的 JavaScript 功能,也再次強調你現正使用中的許多功能其實就是物件。</p>

<table class="learn-box standard-table">
 <tbody>
  <tr>
   <th scope="row">必要條件:</th>
   <td>基本的電腦素養、對 HTML 與 CSS 已有初步認識、熟悉 JavaScript 基本概念 (參閱〈<a href="/zh-TW/docs/Learn/JavaScript/First_steps">First steps</a>〉與〈<a href="/zh-TW/docs/Learn/JavaScript/Building_blocks">Building blocks</a>〉)。</td>
  </tr>
  <tr>
   <th scope="row">主旨:</th>
   <td>了解「物件導向 (OO)」程式設計背後的基礎理論、其與 JavaScript (多屬於物件) 之間的關係、該如何使用 JavaScript 物件進行開發。</td>
  </tr>
 </tbody>
</table>

<h2 id="物件基礎概念">物件基礎概念</h2>

<p>物件是一批相關的數據以及/或者功能(通常包含了幾個變數及函式 — 當它們包含在物件中時被稱做「屬性」(properties)或「函式」(methods)),讓我們用一個範例來看看物件的長相。</p>

<p>在開始之前,請先複製一份 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs.html">oojs.html</a> 檔案到你自己的本端硬碟中。此檔案內容物不多,就 1 組 {{HTMLElement("script")}} 元素可寫入我們的原始碼;在繪製頁面時,1 組元素可輸入簡易指令;幾個變數定義;1 組函式可針對輸入至 input 的程式碼,將之輸出到 {{HTMLElement("p")}} 元素。我們將透過此檔案說明基礎的物件語法。</p>

<p>JavaScript 內的大多數東西,均是透過定義並初始設定變數來建立物件。</p>

<p>現在, 請在自己的 oojs.html 檔案中、JavaScript 程式碼中加入下列程式碼,接著儲存並重新整理:</p>

<pre class="brush: js">var person = {};</pre>

<p>然後在瀏覽器中開啟 oojs.html, 再打開瀏覽器的開發者工具, 在 JavaScript 的控制台下, 輸入<code>person</code>, 並按下 Enter 鈕,就會得到下列結果:</p>

<pre class="brush: js">[object Object]</pre>

<p>恭喜, 你已經建立了自己的第一個物件。但這仍是空的物件,所以能做的事不多。接下來, 再如下所示, 幫 person 物件更新內容:</p>

<pre class="brush: js">var person = {
  name : ['Bob', 'Smith'],
  age : 32,
  gender : 'male',
  interests : ['music', 'skiing'],
  bio : function() {
    alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
  },
  greeting: function() {
    alert('Hi! I\'m ' + this.name[0] + '.');
  }
};
</pre>

<p>改完後同樣儲存 oojs.html、重新整理瀏覽器之後,再到控制台輸入 person, 將會看到新的結果:</p>

<pre class="brush: js">person.name[0]
person.age
person.interests[1]
person.bio()
person.greeting()</pre>

<p>現在你的物件裡面已經有了某些資料與功能,而且能透過某些簡易語法存取之。</p>

<div class="note">
<p><strong>注意:</strong>如果你無法完成上述步驟,可先和我們的版本比較一下。參閱 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-finished.html">oojs-finished.html</a> (或觀看 <a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-finished.html">實際執行</a>)。你最容易犯下的錯誤是在物件中的最後一個成員 (member)末端加上逗號,如此就會造成錯誤。</p>
</div>

<p>目前為止發生了什麼事呢?現在這個物件是由多個成員所構成,各個成員均有 1 個名稱 (如上述的 <code>name</code><code>age</code>) 以及 1 組數值 (如 <code>['Bob', 'Smith']</code><code>32</code>)。由名稱與數值構成的組合均以逗號區隔,而名稱與數值之間則以冒號隔開。語法應如下所示:</p>

<pre class="brush: js">var objectName = {
  member1Name : member1Value,
  member2Name : member2Value,
  member3Name : member3Value
}</pre>

<p>物件成員的數值可能是任何東西,像上述的範例物件就有 1 組字串、1 組數字、2 個陣列、2 組函式。前 4 組項目均為資料項目,可說是該物件的<strong>屬性</strong>。最後 2 組項目的功能則是用以指定物件對該筆資料所應進行的作業,可說是物件的<strong>函式 (Method)</strong></p>

<p>類似這種物件即稱為「<strong>實字物件 (Object literal)</strong>」,按照字面上的意思寫出物件內容;與其相對的就是根據「類別」做出的物件實體。我們稍後會再說明。</p>

<p>在傳送一系列結構化的相關資料項目時 (例如傳送請求至伺服器並置入資料庫中),就常常會透過實字物件的方式建立物件。另與「分別傳送多個項目」相較,送出單一物件當然效率更高,且當你想根據名稱找出各個項目時,更易於搭配陣列。</p>

<h2 id="點記法_(Dot_notation)">點記法 (Dot notation)</h2>

<p>你可透過點記法 (Dot notation) 存取物件的屬性與函式。物件名稱 (這裡是 person) 作為<strong>命名空間 (Namespace)</strong> —為了能存取物件所<strong>封裝</strong>的所有東西,這也是必須首先輸入的項目。接著你寫一個「點」以及你所想存取的項目,可能是簡單屬性的名稱、陣列屬性的項目,又或是針對物件函式之一的呼叫。舉例來說:</p>

<pre class="brush: js">person.age
person.interests[1]
person.bio()</pre>

<h3 id="子命名空間">子命名空間</h3>

<p>甚至可以將物件成員的數值轉為另一個物件。舉例來說,你可將名稱成員從</p>

<pre class="brush: js">name : ['Bob', 'Smith'],</pre>

<p>改變為</p>

<pre class="brush: js">name : {
  first : 'Bob',
  last : 'Smith'
},</pre>

<p>我們這裡以極高效率建立了子命名空間。看起來複雜但其實不然。若要存取這些項目,你只要透過另一個點,將 onto the end 的額外步驟串連起來即可。如下所示:</p>

<pre class="brush: js">person.name.first
person.name.last</pre>

<p><strong>重要:</strong>現在你必須看過自己的函式碼,將實例</p>

<pre class="brush: js">name[0]
name[1]</pre>

<p>改變為</p>

<pre class="brush: js">name.first
name.last</pre>

<p>否則你的函式就不能運作了。</p>

<h2 id="括弧記法_(Bracket_notation)">括弧記法 (Bracket notation)</h2>

<p>括弧記法 (Bracket notation) 是另個存取物件屬性的方法。之前的:</p>

<pre class="brush: js">person.age
person.name.first</pre>

<p>可寫成</p>

<pre class="brush: js">person['age']
person['name']['first']</pre>

<p>這很像在陣列中存取項目的方法。其實基本上是一樣的東西 ─ 但前者是透過指數  (index number) 選擇項目;括弧記法則是透過各成員數值相關的名稱來選擇項目。因此物件有時亦稱作<strong>「相聯陣列 (Associative array)」</strong>;也就是說,其「將字串對應到數值」的方式,與陣列「將數字對應到數值」的方式相同。</p>

<h2 id="設定物件成員">設定物件成員</h2>

<p>到目前為止,我們只說明了檢索 (或<strong>取得</strong>) 物件成員。你也可以簡單宣告你所要設定的成員 (用點或括弧記法均可),設定 (<strong>更新</strong>) 物件成員的數值,如下:</p>

<pre class="brush: js">person.age = 45
person['name']['last'] = 'Cratchit'</pre>

<p>試著輸入下列程式碼,再次取得成員之後看看變更的結果:</p>

<pre class="brush: js">person.age
person['name']['last']</pre>

<p>設定成員不只是更新現有屬性與函式的數值,也可以建立全新的成員,如下:</p>

<pre class="brush: js">person['eyes'] = 'hazel'
person.farewell = function() { alert("Bye everybody!") }</pre>

<p>現在可以測試自己的新成員了:</p>

<pre class="brush: js">person['eyes']
person.farewell()</pre>

<p>此外,括弧記法不僅可動態設定成員數值,亦可設定成員名稱。假設使用者可在自己的人事資料中儲存自訂的數值類型,例如鍵入成員名稱與數值為 2 組文字輸入項,就會類似:</p>

<pre class="brush: js">var myDataName = nameInput.value
var myDataValue = nameValue.value</pre>

<p>接著可將此新的成員名稱與數值加進 <code>person</code> 這個物件:</p>

<pre class="brush: js">person[myDataName] = myDataValue</pre>

<p>若要測試,可將下列程式碼加進自己的程式碼,加在宣告玩 <code>person</code> 物件的大括號後:</p>

<pre class="brush: js">var myDataName = 'height'
var myDataValue = '1.75m'
person[myDataName] = myDataValue</pre>

<p>現在儲存並重新整理,將下列輸入你的文字輸入項中:</p>

<pre class="brush: js">person.height</pre>

<p>因為點記法只接受字母表示的成員名稱,不能是指向名稱的變數值,所以並無法使用。</p>

<h2 id="這個「this」是什麼?">這個「this」是什麼?</h2>

<p>你可能注意到我們函式有怪怪的地方。看看以下範例:</p>

<pre class="brush: js">greeting: function() {
  alert('Hi! I\'m ' + this.name.first + '.');
}</pre>

<p>你可能會想這個「this」是幹嘛用的。「this」是指目前寫入程式碼的物件;所以此範例的 <code>this </code>就等於 <code>person</code>。那又為何不寫 <code>person</code> 就好呢?如同你在〈<a href="/zh-TW/docs/Learn/JavaScript/Objects/Object-oriented_JS">初學者的物件導向 JavaScript</a>〉一文中所看過的,當我們開始設定建構子等東西時,有用的「<code>this</code>」就可在成員內文改變時 (例如 2 個不同 <code>person</code> 物件實例可能具備不同的名稱,但打招呼時仍要使用自己的名稱),確保仍使用了正確的值。</p>

<p>先用簡化的一對 person 物件說明:</p>

<pre class="brush: js">var person1 = {
  name : 'Chris',
  greeting: function() {
    alert('Hi! I\'m ' + this.name + '.');
  }
}

var person2 = {
  name : 'Brian',
  greeting: function() {
    alert('Hi! I\'m ' + this.name + '.');
  }
}</pre>

<p>此範例中的函式碼雖然完全一樣,但 <code>person1.greeting()</code> 將輸出「Hi! I'm Chris.」;<code>person2.greeting()</code> 則會呈現「Hi! I'm Brian.」。如我們剛剛說過的,「<code>this」等於「已於內部放置程式碼」的物件</code>。如果你是依字面意義寫出物件,那可能沒什麼感覺,但如果你是用動態方式產生物件 (例如使用建構子) 的話,就能明顯感覺到方便之處了。再看下去你更清楚原因。</p>

<h2 id="其實你一直在使用物件">其實你一直在使用物件</h2>

<p>隨著你看完這些範例,你應該會覺得跟自己使用的點記法很類似。這是因為你整個課程都在使用點記法。每次我們透過內建的瀏覽器 API 或 JavaScript 物件寫出範例時,我們就是在用物件;因為這些功能也就是以本文提及完全相同的物件結構所寫成。即便是更複雜的範例也是一樣。</p>

<p>所以當你使用字串函式如下:</p>

<pre class="brush: js">myString.split(',');</pre>

<p>你就是在使用 <code><a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/String">String</a></code> 類別實例可用的方法。每次只要你在程式碼中建立字串,該字串就會自動建立成為 <code>String</code> 的實例,並具備有多個常見的方法與屬性。</p>

<p>若你透過下列程式碼存取文件物件模型 (DOM):</p>

<pre class="brush: js">var myDiv = document.createElement('div');
var myVideo = document.querySelector('video');</pre>

<p>你也就在使用 <code><a href="/zh-TW/docs/Web/API/Document">Document</a></code> 類別實例上的函式。當載入網頁時,就會建立 <code>Document</code> 的實例,亦所謂的 <code>document</code>,將呈現整個網頁的架構、內容,以及其他功能 (如網址)。同樣的,這代表其上已有多個常見的函式\屬性。</p>

<p>同理可證,目前你在使用的許多物件\API (如 <code><a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a></code><code><a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Math">Math</a></code> 等) 也都是類似情形。</p>

<p>另該注意的是,內建的物件\API 不見得會自動建立物件實例。像以 <a href="/zh-TW/docs/Web/API/Notifications_API">Notifications API</a>  (它可以幫助你使用現代瀏覽器向使用者發送通知 ) 為例,就需要你針對想要觸發的通知,使用建構子逐一建立新的物件實例。試著將下列程式碼丟進你的 JavaScript 主控台:</p>

<pre class="brush: js">var myNotification = new Notification('Hello!');</pre>

<p>我們會在後續文章中說明建構子 (Constructor)。</p>

<div class="note">
<p><strong>注意:</strong>可思考一下物件「訊息傳遞」的溝通方式。當某個物件需要其他物件執行其他作業時,往往會透過其函式之一傳送訊息給其他物件並等待回應。這也是我們所謂的回傳值。</p>
</div>

<h2 id="摘要">摘要</h2>

<p>恭喜你已經快讀完我們第一篇 JS 物件的文章了。你應該已經知道該如何使用 JavaScript 中的物件,並建立自己的簡單物件了。你也應該了解物件在儲存相關資料的好用之處。如果你將 <code>person</code> 物件中的所有屬性與函式,當做個別的變數與函式並試著追蹤,肯定吃力不討好;且其他具備相同名稱的變數與函式也可能發生問題。「物件」讓我們能在其封包中安全的與資訊相互區隔。</p>

<p>下一篇文章將說明「物件導向程式設計 (OOP)」理論,並了解相關技術是如何用於 JavaScript 之中。</p>

<p>{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}</p>