aboutsummaryrefslogtreecommitdiff
path: root/files/zh-tw/conflicting/learn/javascript/objects/index.html
blob: 292229d00dbd6352265f67eb8547d88b34a59b75 (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
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
---
title: JavaScript 物件導向介紹
slug: Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
tags:
  - 中階
  - 命名空間
  - 封裝
  - 建構子
  - 成員
  - 物件
  - 物件導向
  - 物件導向程式設計
translation_of: Learn/JavaScript/Objects
translation_of_original: Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
---
<div>{{jsSidebar("Introductory")}}</div>

<p>深入淺出物件導向,JavaScript 支援強大、彈性的物件導向程式設計 ({{Glossary("OOP")}})。本篇文章會先介紹物件導向程式設計,然後複習 JavaScript 物件模型,最後示範在 JavaScript 物件導向程式設計的概念。本篇文章並不會介紹 <a href="https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Classes">在 ECMAScript 6 的物件導向程式設計</a> 的新語法。</p>

<h2 id="複習_JavaScript">複習 JavaScript</h2>

<p>若您對 JavaScript 變數、型態、函數及作用範圍的觀念並不是很有信心,您可以閱讀 <a href="/zh-TW/docs/Web/JavaScript/A_re-introduction_to_JavaScript">重新膫解 JavaScript</a> 中相關的主題。您也可以參考 <a href="/zh-TW/docs/Web/JavaScript/Guide">JavaScript 指南</a></p>

<h2 id="物件導向程式設計">物件導向程式設計</h2>

<p>物件導向程式設計 (Object-oriented programming, OOP) 是一種使用 {{glossary("abstraction")}} 概念表達現實世界的程式設計方式。物件導向程式設計運用數個先前所建立的技術所組成,包含模組化 ({{glossary("modularity")}})、多型 ({{glossary("polymorphism")}}) 以及封裝 ({{glossary("encapsulation")}}) 。直到今天許多主流的程式語言 (如 Java, JavaScript, C#, C++, Python, PHP, Ruby 與 Objective-C) 也都支援物件導向程式設計。</p>

<p>物件導向程式設計是將軟體想像成由一群物件交互合作所組成,而非以往以函數 (Function) 或簡單的指令集交互合作所組成。在物件導向的架構中,每個物件都具有接收訊息,處理資料以及發送訊息給其他物件的能力。每個物件都可視為獨一無二的個體,他們扮演不同的角色並有不同的能力及責任。</p>

<p>物作導向程式設計提出了一個一個更有彈性且易於維護的設計方法,且廣泛被許多大型軟體工程所採用。由於物件導向程式設計強調模組化,因為物件導向的程式碼變的較為容易開發且易於理解。與較少模組化的程式設計技術相比,物件導向的程式碼更能更直接分析、編寫、理解複雜的情況與程序。<a href="#cite-1"><sup>1</sup></a></p>

<p>JavaScript 是一個以雛型為基礎 (Prototype-based) 的程式設計語言 (或更準確的說是以雛型為基礎的腳本語言),它採用了複製的模式而非繼承。以雛型為基礎的程式設計語言是一種物件導向程式設計,使用了函數來當做類別 (Class) 的建構子 (Constructor),儘管 JavaScript 擁有類別 (Class) 的關鍵字,但它沒有類別敘述,當要拿 JavaScript 與其他物件導向程式語言相比時,這是很重要的區別。</p>

<h2 id="專門用語">專門用語</h2>

<dl>
 <dt>{{Glossary("Namespace")}}</dt>
 <dd>可讓開發人員包裝所有功能到一個獨一無二、特定應用程式名稱的容器。</dd>
 <dt>{{Glossary("Class")}}</dt>
 <dd>用來定義物件的特徵,類別 (Class) 是物件屬性與方法的藍圖。</dd>
 <dt>{{Glossary("Object")}}</dt>
 <dd>類別 (Class) 的實際案例。</dd>
 <dt>{{Glossary("Property")}}</dt>
 <dd>物件 (Object) 的特徵,例如:顏色。</dd>
 <dt>{{Glossary("Method")}}</dt>
 <dd>物件 (Object) 的功能,例如:行走。它是與類別相關的子程序或函數。</dd>
 <dt>{{Glossary("Constructor")}}</dt>
 <dd>一個在物件產生時會被呼叫的方法。通常會使用與其所在類別 (Class) 相同的名稱。</dd>
 <dt>{{Glossary("Inheritance")}}</dt>
 <dd>一個類別 (Class) 可以繼承另一個類別的特徵與功能。</dd>
 <dt>{{Glossary("Encapsulation")}}</dt>
 <dd>可以將資料與方法包裝在一起使用的技術。</dd>
 <dt>{{Glossary("Abstraction")}}</dt>
 <dd>結合物件的複雜繼承關係、方法與屬性來充分反映現實的模型。</dd>
 <dt>{{Glossary("Polymorphism")}}</dt>
 <dd>Poly 指的是 "多" 而 Morphism 指的是 "<em></em>"。是指不同的類別可以定義相同的方法或屬性。</dd>
</dl>

<p>要了解物件導向程式設計更廣泛的說明,請參考維基百科的  {{interwiki("wikipedia", "Object-oriented programming")}}</p>

<h2 id="以雛型為基礎_Prototype-based_的程式設計">以雛型為基礎 (Prototype-based) 的程式設計</h2>

<p>以雛型為基礎的程式設計是一種不使用類別的物件導向程式設計模式,但它是第一個透過修改 (或者擴充) 既有的 <em>prototype</em> 來達到類別的功能並可重複使用 (等同在以類別為基礎的程式語言中的繼承)。 又稱作無類別 (Classless)、雛型導向 (Prototype-oriented) 或以實例為基的程式語言 (Instance-based programming)。</p>

<p>最早 (最典型) 以雛型為基礎的程式語言的典範是由 David Ungar 與 Randall Smith 所開發的 {{interwiki("wikipedia", "Self (programming language)", "Self")}}。近年來無類別 (Class-less) 的程式設計風格越來越流行,並且被 JavaScript, Cecil, NewtonScript, Io, MOO, REBOL, Kevo, Squeak (在使用 Viewer 框架來處理 Morphic 元件時),還有許多其他程式語言所採用。<a href="#cite-2"><sup>2</sup></a></p>

<h2 id="JavaScript_物件導向程式設計">JavaScript 物件導向程式設計</h2>

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

<p>命名空間是一個可讓開發人員包裝所有功能到一個獨一無二、特定應用程式名稱的容器。在<strong> JavaScript 中命名空間其實是另一個包含方法、屬性及物件的物件。</strong></p>

<div class="note">
<p>注意,在 JavaScript 中一般物件與命名空間並無語法上的差異,這於其他許多物件導向的語言並不相同,可能是初學 JavaScript 的程式設計師容易混淆的地方。</p>
</div>

<p>在 JavaScript 建立一個命名空間背後的概念非常的簡單:建立一個全域的物件,然後將所有的變數、方法及函數設為該物件的屬性。使用命名空間可以減少應用程式中名稱衝突發生的機率,由於每個應用程式的物件皆會是應用程式定義的全域物件的屬性。</p>

<p>讓我們來建立一個叫做 MYAPP 全域物件:</p>

<pre class="brush: js notranslate">// 全域命名空間
var MYAPP = MYAPP || {};</pre>

<p>在上述程式範例,我們會先檢查 <code>MYAPP</code> 是否已經定義過 (不論是定義在同一檔案或在其他檔案)。若已定義過,便會使用現有的 MYAPP 全域物件,否則會建一個稱作 <code>MYAPP</code> 的空物件來包裝方法、函數、變數及物件。</p>

<p>我們也可以建立子命名空間 (要注意,全域物件必須已事先定義):</p>

<pre class="brush: js notranslate">// 子命名空間
MYAPP.event = {};</pre>

<p>以下的程式碼會建立一個命名空間並加入變數、函數以及一個方法:</p>

<pre class="brush: js notranslate">// 建立一個稱作 MYAPP.commonMethod 的容器來存放常用方法與屬性
MYAPP.commonMethod = {
  regExForName: "", // define regex for name validation
  regExForPhone: "", // define regex for phone no validation
  validateName: function(name){
    // Do something with name, you can access regExForName variable
    // using "this.regExForName"
  },

  validatePhoneNo: function(phoneNo){
    // do something with phone number
  }
}

// 物件與方法宣告
MYAPP.event = {
    addListener: function(el, type, fn) {
    // code stuff
    },
    removeListener: function(el, type, fn) {
    // code stuff
    },
    getEvent: function(e) {
    // code stuff
    }

    // 可以加入其他方法與屬性
}

// 使用 addListener 方法的語法:
MYAPP.event.addListener("yourel", "type", callback);</pre>

<h3 id="標準內建物件">標準內建物件</h3>

<p> JavaScript 的核心內建了許多物件,例如有 {{jsxref("Math")}}, {{jsxref("Object")}}, {{jsxref("Array")}} 以及 {{jsxref("String")}}。以下範例將示範如何使用 Math 物件中的 <code>random()</code> <code>方法</code>來取得一個隨機的數字。</p>

<pre class="brush: js notranslate">console.log(Math.random());
</pre>

<div class="note"><strong>注意:</strong>這個例子及之後的例子會假設全域已經有定義名稱為 {{domxref("console.log()")}} 的函數。<code>console.log()</code> 函數並不算是 JavaScript 的一部份,但是有許多瀏覽器會實作這個功能來協助除錯使用。</div>

<p>請參考 <a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects" title="zh-TW/docs/Web/JavaScript/Reference/Global_Objects">JavaScript 參考: 標準內建物件</a> 來取得在 JavaScript 中所有核心物件的清單。</p>

<p>每個在 JavaScript 中的物件均為物件 <code><a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a></code> <code></code>實例 (Instance),因此會繼承其所有的屬性與方法。</p>

<h3 id="自訂物件">自訂物件</h3>

<h4 id="類別_Class">類別 (Class)</h4>

<p>JavaScript 是以雛形為基礎的程式語言,並沒有像在 C++ 或 Java 中看以到的 <code>class</code> 敘述句,這有時會讓習慣使用有 <code>class</code> 敘述句的程式設計師混淆。JavaScript 使用函數來作為類別 (Class) 的建構子 (Constructor),要定義一個類別 (Class) 如同定義一個函數 (Function)一樣簡單,以下例子中我們使用空的建構子來定義了一個新的 Person 類別。</p>

<pre class="brush: js notranslate">var Person = function () {};
</pre>

<h4 id="物件_Object_-_類別的實例_Instance">物件 (Object) - 類別的實例 (Instance)</h4>

<p>要建立物件 <code>obj</code> 的新實例,我們可以使用 <code>new obj</code> 敘述句,並將結果 (型態為 <code>obj</code>) 指派 (Assign) 到一個變數方便之後存取。</p>

<p>在先前範例中我們定義了一個名稱為 <code>Person</code> 的類別 (Class)。在以下的例子我們會建立兩個實例 (<code>person1</code><code>person2</code>)。</p>

<pre class="brush: js notranslate">var person1 = new Person();
var person2 = new Person();
</pre>

<div class="note">
<p>請參考 {{jsxref("Object.create()")}} 來了解建立未初始化實例的實例化新方法。</p>
</div>

<h4 id="建構子_Constructor">建構子 (Constructor)</h4>

<p>建構子會在實例化 (Instantiation) 時被呼叫 (建立物件實例被建立時)。建構子是類別的一個方法,在 JavaScript 中會以函數來當做物件的建構子,因此無須明確的定義建構子方法,而每個在類別中宣告的動作均會在實例化時被執行。</p>

<p>建構子會用來設定物件的屬性 (Property) 或是呼叫要準備讓物件可以使用的方法 (Method)。增加類別的方法及定義會使用另一種語法,在本文稍後會說明。</p>

<p>在以下例之中,類別 <code>Person</code> 的建構子在 <code>Person </code>實例化時會記錄下一個訊息。</p>

<pre class="brush: js notranslate">var Person = function () {
  console.log('instance created');
};

var person1 = new Person(); // 會記錄 "instance created"
var person2 = new Person(); // 會記錄 "instance created"
</pre>

<h4 id="屬性_Property_-_物件的屬性">屬性 (Property) - 物件的屬性</h4>

<p>屬性即為在類別中的變數,每個物件的實例都會有同樣的屬性。屬性會在類別的建構子 (函數) 中設定,所以屬性在每個實例產生時才會產生。</p>

<p>關鍵字 <code>this </code>可以引用目前的物件,讓您使用在該類別中的其他屬性。存取 (讀寫或寫入) 一個在類別之外的屬性可以用語法:<code>InstanceName.Property</code>,如同在 C++, Java 以及其他語言。 (在類別內會使用語法 <code>this.Property</code> 來取得或設定屬性的數值。)</p>

<p>在以下例子中,我們會在實例化時定義 <code>Person</code> 類別的 <code>firstName</code> 屬性:</p>

<pre class="brush: js notranslate">var Person = function (firstName) {
  this.firstName = firstName;
  console.log('Person instantiated');
};

var person1 = new Person('Alice'); // 會記錄 "Person instantiated"
var person2 = new Person('Bob'); // 會記錄 "Person instantiated"

// 顯示物件的 firstName 屬性
console.log('person1 is ' + person1.firstName); // 會記錄 "person1 is Alice"
console.log('person2 is ' + person2.firstName); // 會記錄 "person2 is Bob"
</pre>

<h4 id="方法_Method">方法 (Method)</h4>

<p>方法即為函數 (也如同函數般定義),但是依照屬性的邏輯來運作,呼叫一個方法如同存取一個屬性,但您需要在函數名稱後加上 <code>()</code> ,並有可能會有參數。要定義一個方法,只需將函數指定 (Assign) 給類別的 <code>prototype</code> 屬性中一個已命名的屬性,接著,您便可用剛指定的屬性名稱來呼叫該物件的方法。</p>

<p>以下範例中,我們為 <code>Person</code>  類別定義了方法 <code>sayHello()</code> 並使用。</p>

<pre class="brush: js notranslate">var Person = function (firstName) {
  this.firstName = firstName;
};

Person.prototype.sayHello = function() {
  console.log("Hello, I'm " + this.firstName);
};

var person1 = new Person("Alice");
var person2 = new Person("Bob");

// 呼叫 Person sayHello 方法。
person1.sayHello(); // 會記錄 "Hello, I'm Alice"
person2.sayHello(); // 會記錄 "Hello, I'm Bob"
</pre>

<p>在 JavaScript 中,方法其實是一般的函數物件 (Function object) 連結到一個物件的屬性,這意謂著您可以在  "物件之外" 呼叫方法。請看以下範例程式碼:</p>

<pre class="brush: js notranslate">var Person = function (firstName) {
  this.firstName = firstName;
};

Person.prototype.sayHello = function() {
  console.log("Hello, I'm " + this.firstName);
};

var person1 = new Person("Alice");
var person2 = new Person("Bob");
var helloFunction = person1.sayHello;

// 會記錄 "Hello, I'm Alice"
person1.sayHello();

// 會記錄 "Hello, I'm Bob"
person2.sayHello();

// 會記錄 "Hello, I'm undefined" (或在 Strict
// 模式會出現 TypeError)
helloFunction();

// 會記錄 true
console.log(helloFunction === person1.sayHello);

// 會記錄 true
console.log(helloFunction === Person.prototype.sayHello);

// 會記錄 "Hello, I'm Alice"
helloFunction.call(person1);</pre>

<p>如範例中所示,我們讓所有的參考均指向 <code>sayHello</code> 函數 — 一個在 <code>person1、一個在 Person.prototype、另一個在 helloFunction</code> 變數 — 這些均參考<em>相同的函數</em>。在呼叫的過程中 <code>this</code> 的值會根據我們如何呼叫來決定,最常見的地方是:我們取得函數的物件屬性所在,在表示法中呼叫 <code>this</code> — <code>person1.sayHello()</code>— 會設定 <code>this</code> 為我們取得函數的地方 (<code>person1</code>),這也是 <code>person1.sayHello() 顯示的名稱為 </code>"Alice" 以及 <code>person2.sayHello() 顯示的</code>名稱為 "Bob" 的原因。但如果我們以其他的方式來呼叫,那麼 <code>this</code> 結果將截然不同:在變數中呼叫 <code>this</code> — <code>helloFunction()</code>— 會設定 <code>this</code> 為所在的全域物件 (在瀏覽器即為 <code>window</code>)。由於物件 (可能) 並沒有 <code>firstName</code> 屬性,因此會得到 "Hello, I'm undefined" 這樣的結果 (在 Loose 模式才有這樣的結果,若在 <a href="/zh-TW/docs/Web/JavaScript/Reference/Strict_mode" title="/en/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode">strict mode</a> 則會不同 [會出現錯誤],為了避免混淆,此處將不會再詳述)。 或者我們可以像最後一個例子使用 <a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Function/call">call</a> (或 <a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Function/apply">apply</a>) 來明確的設定 <code>this。</code></p>

<div class="note"><strong>注意:</strong>請參考 <a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Function/call" title="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call">call</a> 及 <a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Function/apply" title="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply">apply</a> 來取得更多有關 <code>this</code> 的資訊</div>

<h4 id="繼承">繼承</h4>

<p>繼承是一種用一個或多個類別建立一個特殊版本類別的方式 (<em>JavaScript 僅支援單一繼承</em>)。這個特殊的類別通常稱做<em>子類別</em>,而其引用的類別則通常稱作<em>父類別</em>。在 JavaScript 您可以指定父類別的實例到子類別來做到這件事。在最近的瀏覽器中您也可以使用 <a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Classical_inheritance_with_Object.create" title="/zh-TW/docs/JavaScript/Reference/Global_Objects/Object/create#Classical_inheritance_with_Object.create">Object.create</a> 來實作繼承。</p>

<div class="note">
<p><strong>注意:</strong>JavaScript 不會偵測子類別的 <code>prototype.constructor</code> (請參考 <a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype">Object.prototype</a>),所以我們必須手動處理。請參考在 Stackoverflow 的問題 "<a href="https://stackoverflow.com/questions/8453887/why-is-it-necessary-to-set-the-prototype-constructor">為什麼一定要設定 prototype 的建構子?</a>"。</p>
</div>

<p>於以下範例,我們會定義類別 <code>Student</code> 做為 <code>Person</code> 的子類別。然後我們會重新定義 <code>sayHello()</code> 方法然後加入 <code>sayGoodBye()</code> 方法。</p>

<pre class="brush: js notranslate">// 定義 Person 建構子
var Person = function(firstName) {
  this.firstName = firstName;
};

// 加入兩個方法到 Person.prototype
Person.prototype.walk = function(){
  console.log("I am walking!");
};

Person.prototype.sayHello = function(){
  console.log("Hello, I'm " + this.firstName);
};

// 定義 Student 建構子
function Student(firstName, subject) {
  // Call the parent constructor, making sure (using call)
  // that "this" is set correctly during the call
  Person.call(this, firstName);

  // Initialize our Student-specific properties
  this.subject = subject;
}

// 建立 Student.prototype 物件來繼承 Person.prototype。
// 注意: 在此處經常見的錯誤是使用 "new Person()" 來建立
// Student.prototype。不正確的原因許多個,尤其是
// 我們沒有給予 Person 任何 "firstName" 的參數。
// 呼叫 Person 的正確位置在上方,也就是我們呼叫 Student
// 的地方。
Student.prototype = Object.create(Person.prototype); // 詳見以下說明

// 設定 "constructor" 屬性參考 Student
Student.prototype.constructor = Student;

// 替換 "sayHello" 方法
Student.prototype.sayHello = function(){
  console.log("Hello, I'm " + this.firstName + ". I'm studying "
              + this.subject + ".");
};

// 加入"sayGoodBye" 方法
Student.prototype.sayGoodBye = function(){
  console.log("Goodbye!");
};

// 範例用法:
var student1 = new Student("Janet", "Applied Physics");
student1.sayHello();   // "Hello, I'm Janet. I'm studying Applied Physics."
student1.walk();       // "I am walking!"
student1.sayGoodBye(); // "Goodbye!"

// 檢查 instanceof 可正常運作
console.log(student1 instanceof Person);  // true
console.log(student1 instanceof Student); // true
</pre>

<p><code>Student.prototype = Object.create(Person.prototype);</code> 一行:在舊版的 JavaScript 引擎沒有 <a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object/create" title="Object.create"><code>Object.create</code></a>,可以使用 "polyfill" (又稱 "shim",請參考以下文章連結) 或使用函數來達到同樣的效果,如:</p>

<pre class="brush: js notranslate">function createObject(proto) {
    function ctor() { }
    ctor.prototype = proto;
    return new ctor();
}

// 用法:
Student.prototype = createObject(Person.prototype);
</pre>

<div class="note"><strong>注意:</strong> 請參考 <a href="/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object/create" title="Object.create">Object.create</a> 來了解其功能與舊引擎使用的 shim。</div>

<p>要在不管物件如何實例化的情況下確保 <code>this</code> 指向正確的地方並不簡單,儘管如此,這裡仍有一個簡單的習慣用法讓這件事變的較簡單。</p>

<pre class="brush: js notranslate">var Person = function(firstName) {
  if (this instanceof Person) {
    this.firstName = firstName;
  } else {
    return new Person(firstName);
  }
}
</pre>

<h4 id="封裝">封裝</h4>

<p>於上述例子中 <code>Student</code> 並不需要知道 <code>Person</code> 類別的 <code>walk()</code> 方法實作的方式,但仍可以使用該方法,除非我們想要更改該函數,否則 <code>Student</code> 類別並不需要明確的定義該函數。這樣的概念稱就叫作<strong>封裝 (Encapsulation)</strong>,透過將每個類別的資料與方法包裝成一個單位。</p>

<p>隱藏資訊在其他語言是常見的功能,通當會使用私有 (Private) 與保護 (Protected) 方法/屬性。既使如此,您仍可在 JavaScript 模擬類似的操作,這並不是物件導向程式設計必要的功能。<a href="#cite-3"><sup>3</sup></a></p>

<h4 id="抽象化">抽象化</h4>

<p>抽象化是一個機制能讓您將工作問題的目前部份進行建立模型,不論是用繼承 (特殊化) 或是組合的方式。JavaScript 可以透過繼承達到特殊化 (Specialization),並可讓類別實例成為其他物件的屬性來達到組合 (Composition)。</p>

<p>JavaScript 的 Function 類別繼承 Object 類別 (這示範了模型的特殊化) 而 {{jsxref("Function.prototype")}} 屬性是 {{jsxref("Object")}} 的實例 (這示範了組合)。</p>

<pre class="brush: js notranslate">var foo = function () {};

// 會記錄 "foo is a Function: true"
console.log('foo is a Function: ' + (foo instanceof Function));

// 會記錄 "foo.prototype is an Object: true"
console.log('foo.prototype is an Object: ' + (foo.prototype instanceof Object));</pre>

<h4 id="Polymorphism" name="Polymorphism">多型</h4>

<p>如同所有方法與屬性會定義在 prototype 之中,不同的類別可以定義相同名稱的方法,而這些方法的有效範圍其所在的類別之中,除非兩個類別之間有父子關係 (例如,其中一個類別是繼承另一個類別而來)。</p>

<h2 id="注意">注意</h2>

<p>在 JavaScript 並不是只有這些方式可以實作物件導向程式設計,JavaScript 在這方面非常有彈性。另外,在此處示範的方法並沒有使用任何語言特殊技巧,也沒有模仿其他語言的物件理論來實作。</p>

<p>在 JavaScript 也有其他的方式可以做更進階的物件導向程式設計,但已超出本篇簡介的範圍。</p>

<h2 id="參考文獻">參考文獻</h2>

<ol>
 <li><a href="https://en.wikipedia.org/wiki/Object-oriented_programming" id="cite-1">Wikipedia - Object-oriented programming</a></li>
 <li><a href="https://en.wikipedia.org/wiki/Prototype-based_programming" id="cite-2">Wikipedia - Prototype-based programming</a></li>
 <li><a href="http://en.wikipedia.org/wiki/Encapsulation_%28object-oriented_programming%29" id="cite-3">Wikipedia - Encapsulation (object-oriented programming)</a></li>
</ol>

<h2 id="相關資料">相關資料</h2>

<ul>
 <li>{{jsxref("Function.prototype.call()")}}</li>
 <li>{{jsxref("Function.prototype.apply()")}}</li>
 <li>{{jsxref("Object.create()")}}</li>
 <li><a href="/zh-TW/docs/Web/JavaScript/Reference/Strict_mode">嚴謹模式 (Strict mode)</a></li>
</ul>