代碼詳解:使用JavaScript進行面向對象編程的指南
一切都從對象開始。
對象,即我們相互交流的一個載體,有其屬性和方法。對象是面向對象編程的核心,不僅用于JavaScript,而且還適用于Java、C語言、C++等。不再考慮單個變量和函數,而選擇自給型的對象。
以下是在討論面向對象編程(OOP)時最常用到的概念:
- 對象,屬性,方法
- 類
- 封裝
- 抽象
- 復用/繼承
- 多態性
- 關聯
- 聚合
- 組合
1. 對象,屬性,方法
1.1 對象字面量(Objectliteral)
在大括號中設置屬性,從而在JavaScript中創建一個新對象。對象字面量屬性值可以是任何數據類型,如函數字面量、數組、字符串、數字或布爾值。
下面創建一個命名圖書的對象,其屬性包括作者、出版年份、標題和方法。
- — summary.
- constbook = {
- title: "Hippie",
- author: "Paulo Coelho",
- year: "2018"
- }
對象創建完成后,可以使用點記法獲取值。例如,可以使用book.title.獲取標題的值,還可以使用方括號book[‘title’]訪問屬性。
1.2 對象構造函數(Objectconstructor)
對象構造函數與常規函數相同。每次創建對象時都會用到。可將其與新關鍵字一起使用。當需要創建具有相同屬性和方法的多個對象時,對象構造函數非常有用。
- constbook = {
- title: "Hippie",
- author: "Paulo Coelho",
- year: "2018"
- }const book1 = {
- title: "The Alchemist",
- author: "Paulo Coelho",
- year: "1988",
- }
如果要創建多個書籍(book)對象,必須為每本書復制代碼。可以繼續創建 book對象,但這有點麻煩——不過對象構造函數有助于再次使用對象字面量。
- functionBook(title, author, year) {
- this.title = title;
- this.author = author;
- this.year = year;
- }const book1 = new Book ('Hippie', 'Paulo Coelho',
- '2018');
- console.log(book1);
- > Book {
- title: "Hippie",
- author: "Paulo Coelho",
- year: "2018"
- }// if we want to create more than onebook just we call
- function book with new keyword.const book2
- = new Book ('TheAlchemist', 'Paulo Coelho', '1988');
book1 和 book2創建 Book的實例并將其分配給變量。想知道一個對象是否是另一個對象的實例。可以用instanceof。
- book1 instanceof Book
- > true
1.3 Object.create()方法
JavaScript中的每個對象都將從主對象創建。任何時候使用大寫字母“O”時,指的都是主對象。我們可以在console控制臺中打印主對象。主對象有很多方法,下面來看object.create()方法。

Object.create()創建法使用現有對象作為原型來創建新對象。基本語法如下:
- Object.create(proto,[propertiesObject])
proto是新建對象的原型。 propertiesObject是一個可選項。
下面舉個簡單的例子:
- constBook = {
- summary : function() {
- console.log(`${this.title} iswritten by ${this.author}.`)
- }
- }const book1 = Object.create(Book);
- book1.author = "Paulo Coelho";
- book1.title = "Hippie";console.log(book1.summary());
- > Hippie is written by Paulo Coelho.
以上的例子創建了一個原始對象book1,并為作者和標題賦值。可以看到原始對象中的匯總函數:

下面將Object.create() 方法進行詳細介紹。
2. 類
類不是對象,它是對象的藍本,是特殊函數。可以使用函數的表達式和聲明來定義函數,也可以這樣定義類。藍本可用來表示對象的數量。
可以使用類的關鍵字和名稱。語法與Java相似。
類語法是使用面向對象編程和管理原型的一個好途徑:
- let Book= function(name) {
- this.name = name
- }let newBook = function(name) {
- Book.call(this, name)
- } newBook.prototype = Object.create(Book.prototype);
- const book1 = new newBook("The Alchemist");
此例使用了ES6類語法:
- classBook {
- constructor(name) {
- this.name = name
- }
- }class newBook extends Book {
- constructor(name) {
- super(name);
- }
- }const book1 = new newBook("The Alchemist");
類語法是語法糖(syntactical sugar)—而場景背后它仍然使用基于原型的模型。類是函數,而函數是JavaScript中的對象。
- classBook {
- constructor(title, author){
- this.title = title;
- this.author = author;
- }
- summary() {
- console.log(`${this.title} writtenby ${this.author}`);
- }
- }const book1 = new Book("", "");
- console.log(typeof Book);
- > "function"console.log(typeof book1);
- > "object"
3. 封裝(Encapsulation)
封裝意為隱藏信息或數據。指對象在不向外部使用者透露任何執行細節的情況下執行其功能。換句話說,就是其私有變量只對當前函數可見,而對全局范圍或其他函數不可訪問。
- constBook = function(t, a) {
- let title = t;
- let author = a;
- return {
- summary : function() {
- console.log(`${title} written by${author}.`);
- }
- }
- }
- const book1 = new Book('Hippie', 'Paulo Coelho');
- book1.summary();
- > Hippie written by Paulo Coelho.
在上面的代碼中,標題和作者只在函數Book 的范圍內可見,方法summary對Book的使用者可見。所以書名和作者被封裝在Book中。
4. 抽象
抽象意為實現隱藏。它是一種隱藏實現細節的方法,只向使用者顯示基本特性。換句話說,它隱藏了不相關的細節,只顯示了必須對外部世界顯示的。缺乏抽象會導致代碼出現可維護性問題。
- constBook = function(getTitle, getAuthor) {
- // Private variables / properties
- let title = getTitle;
- let author = getAuthor;// Publicmethod
- this.giveTitle = function() {
- return title;
- }
- // Private method
- const summary = function() {
- return `${title} written by${author}.`
- }// Public method that has access toprivate method.
- this.giveSummary = function() {
- return summary()
- }
- }const book1 = new Book('Hippie', 'Paulo Coelho');
- book1.giveTitle();
- > "Hippie"book1.summary();
- > Uncaught TypeError: book1.summary is not a
- functionbook1.giveSummary();
- > "Hippie written by Paulo Coelho."
5. 復用/繼承
JavaScript繼承是一種機制,允許我們使用現有的類創建一個新類。也就是子類繼承父類的所有屬性和行為。
一般來說,JavaScript不是一種基于類的語言。關鍵字“類”是在ES6中引入的,但它是語法糖,JavaScript仍然是基于原型的。在JavaScript中,繼承是通過使用原型來實現的。這種模式稱為行為委托模式或原型繼承。
同樣可以通過book例子來體現:
- functionBook(title, author, year) {
- this.title = title;
- this.author = author;
- this.year = year;
- this.summary = function() {
- console.log(`${this.title} iswritten by ${this.author}.`)
- }
- }
- const book1 = new Book ('Hippie', 'Paulo Coelho', '2018');
- const book2 = newBook ('The Alchemist', 'Paulo Coelho',
- '1988');
原型繼承
對于Book的每個實例,我們都在為基類中的方法重建內存。這些方法必須在所有實例之間共享 — 不應特定于個別實例中。圖中的原型是:
- letCorebook = function(title) {
- this.title = title
- }Corebook.prototype.title = function() {
- console.log(`name of the book is${this.title}`);
- }Corebook.prototype.summary = function(author) {
- console.log(`${this.title} is writtenby ${this.author}`);
- }let Book = function(title, author) {
- Corebook.call(this, title, author)
- }Book.prototype = Object.create(Corebook.prototype);
- let book1
- = new Book('TheAlchemist', 'Paulo Coelho');book1.title();
- > name of the book is The Alchemistbook1.summary();
- > The Alchemist is written by Paulo Coelho
在上面的代碼中,Book 的實例有一個原型的副本,能夠鏈接到Book的原型,而Book的原型又鏈接到Corebook的原型。
6. 多態
在不同的對象上使用同一方法,并讓每個對象具有自己的表現形式或形態的能力,稱為多態。
- letbook1 = function () {}
- book1.prototype.summary = function() {
- return "summary of book1"
- }let book2 = function() {}
- book2.prototype = Object.create(book1.prototype);
- book2.prototype.summary = function() {
- return "summary of book2"
- }let book3 = function() {}
- book3.prototype = Object.create(book1.prototype);
- book3.prototype.summary = function() {
- return "summary of book3"
- }
- var books = [new book1(), new book2(), new book3()];
- books.forEach(function(book){
- console.log(book.summary());
- });> summary of book1
- > summary of book2
- > summary of book3
對象之間的關系將由關聯、聚合和組合定義。
7. 關聯
關聯是兩個或多個對象之間的關系。每個對象都是獨立的。換句話說,關聯定義了對象之間的多重性:一對一、一對多、多對一、多對多。
- functionBook(title, author) {
- this.title = title;
- this.author = author;
- }
- const book1 = new Book ('Hippie', 'Paulo Coelho');
- const book2 = new Book ('TheAlchemist',
- 'Paulo Coelho');
- book2.multiplicity
- = book1
book1 賦值于book2的屬性多樣化,顯示對象book1 和 book2之間的關系。兩者都可以獨立添加和刪除。

8. 聚合
聚合是關聯的特例。在兩個對象之間的關系中,一個對象可能比另一個更重要。換句話說,當一個對象比另一個擁有更多的所有權時,這就是聚合。對象所有者通常稱為聚合,被所有者稱為組件。聚合又叫“Has-a”關系。
- functionBook(title, author) {
- this.title = title;
- this.author = author;
- }
- const book1 = new Book ('Hippie', 'Paulo Coelho');
- const book2 = new Book ('TheAlchemist', 'Paulo Coelho');
- let publication = {
- "name": "new publicationInc",
- "books": []
- }publication.books.push(book1);
- publication.books.push(book2);
book1 和 book2 被添加到對象publication下設的books中。如果在book1和book2 運行之后刪除publication,則 Book和 publication 都將獨立運行。

9. 組合
組合是聚合的一種特殊情況。一個對象包含另一個對象,并且被包含的對象脫離后無法生存。
- let Book= {
- "title": "TheAlchemist",
- "author": "PauloCoelho",
- "publication": {
- "name": "newpublication Inc",
- "address":"chennai"
- }
- }
這里屬性publication與 Book 對象有嚴格的限制,publication不能沒有Book對象。如果Book的id被刪除,則publication也將被刪除。
重組合輕繼承
繼承指一個對象基于另一個對象的情況。例如,book1繼承了標題、作者和結語等書籍的屬性和方法,所以它建立了book1 is-a Book關系。
組合是收集單一對象并將它們組合起來構建更復雜的對象。為構建book1,需要一些方法,比如紙和筆。因此book1 has-a paper and a pen關系隨之出現。
- constgetTitle = (data) => ({
- title : () => console.log(`title :${data.title}`)
- });const getAuthor = (data) => ({
- author : () => console.log(`author:${data.author}`)
- });const getSummary = () => ({
- summary :() => console.log(`booksummary need to
- update.`)
- });const Book = (title, author) => {
- const data = {
- title,
- author
- }
- return Object.assign({},
- getTitle(data),
- getAuthor(data),
- getSummary()
- )
- }let book1 = Book('The Alchemist', 'Paulo Coelho');
- book1.title();
- > "title : The Alchemist"