2009-01-14 44 views
39

我一直在使用javascript一段時間,但從來沒有學過基本的語言。我正在閱讀John Resig的「專業Javascript技術」 - 我提出了一些問題,但我沒有在書或谷歌等網站上找到答案。Javascript中的面向對象問題

John在他的書中給出了這個例子:
功能#1

function User(name, age){ 
    this.name = name; 
    this.age = age; 
} 
// Add a new function to the object prototype 
User.prototype.getName = function(){ 
    return this.name; 
}; 
User.prototype.getAge = function(){ 
    return this.age; 
}; 
var user = new User("Bob", 44); 
console.log("User: " + user.getName() + ", Age: " + user.getAge()); 

我還在學習有關原型財產,所以我試着寫類似的東西:
功能#2

function User (name, age) { 
    this.name = name; 
    this.age = age; 
    this.getName = function() { 
    return this.name; 
    }; 
    this.getAge = function() { 
    return this.age; 
    }; 
} 
var user = new User("Bob", 44); 
console.log("User: " + user.getName() + ", Age: " + user.getAge()); 

它不使用原型屬性創建的getName和getAge功能,但輸出是一樣的約翰的例子。

我把它一步,並創造了這個:
功能#3

var User = { 
    name: "", 
    age: 0, 
    setName: function(name) { 
    this.name = name; 
    }, 
    setAge: function(age) { 
    this.age = age; 
    }, 
    getName: function() { 
    return this.name; 
    }, 
    getAge: function() { 
    return this.age; 
    } 
}; 
User.setName("Bob"); 
User.setAge(44); 
console.log("User: " + User.getName() + ", Age: " + User.getAge()); 

再次 - 它看起來不同於約翰的例子(我不得不添加setter方法),但輸出是一樣的。

問題#1 - 3個功能之間有什麼區別?原型屬性的優點是什麼,函數#2做了什麼不正確的事情,因爲它似乎更直接地代碼#2而不是#1(儘管我確信#1正在做的更好,看到約翰創建它) 。

問題#2 - 如何修改函數#3以不使用setName和setAge方法,但仍保留{...}簡寫形式? {...}速記可以有構造函數嗎?

在此先感謝幫助我學習!

編輯 我覺得我的第二個問題有點混亂。我的意思是,我怎麼能使用{...}速記創建一個User對象,但後來經過我創建的對象,這樣說:

var user = new User("Bob", 44); 

就像在功能#1 - 或者是不可能的?

編輯#2 哇!謝謝大家的真棒答案。這真的讓我更加清楚。所以如果我理解正確的話,#1和#2之間的差別不是太大。如果我只創建一個「用戶」對象 - 它們可能根本就沒有什麼不同。但是,如果我的程序創建了許多用戶對象,#1很可能會更有效率,並使用更少的內存,因爲所有對象都將共享相同的功能。

我真的很感謝所有的好的答案 - 謝謝!

回答

22

每次函數(){}被評估時,它都會創建一個新的函數對象。因此,#1中的所有User對象都共享相同的getName和getAge函數,但在#2和#3中,每個對象都有自己的getName和getAge副本。所有不同的getName函數都表現得完全一樣,所以你不能在輸出中看到任何差異。

{...}速記的構造函數。評估時,它會用給定的屬性構造一個新的「對象」。當你運行「新用戶(...)」時,它會構建一個新的「用戶」。您碰巧創建了與用戶具有相同行爲的對象,但它們的類型不同。

迴應評論:

你不能,直接。您可以創建一個按照#3創建新對象的函數。例如:

function make_user(name, age) { 
    return { 
     name: name, 
     age: age, 
     getName: function() { return name; }, 
     getAge: function() { return age; }, 
    }; 
} 

var user = make_user("Joe", "18"); 
+0

我想我的意思是問題#2是如何修改函數#3,這樣我可以這樣說變種人=新用戶(); – BrianH 2009-01-14 18:53:44

+0

該評論並不完全正確「所有不同的getName函數都表現完全一樣」。類型#2有權訪問私人股票交易所 – meouw 2009-01-14 20:12:32

+0

我的觀點是他們的行爲在這個例子中是一樣的。 – Glomek 2009-01-14 20:18:01

5

2:

您可以訪問名字和年齡,不使用這樣的功能。在JavaScript中,您必須使用不同的黑客手段來保護私密或受保護的內容。

User.name = "BoB"; 
User.age = 44; 

會產生相同的輸出的例子。

沒有構造函數,因爲它們以其他語言顯示。最簡單的方法是定義init()函數並在實例化對象後立即調用它。

但我最大的提示是查看http://www.prototypejs.org/。這是一個JavaScript庫,其中有很多很酷的功能,它們試圖讓javascript「更多OO *」。

使用原型庫可以使類更像真正的OOP類。它還具有構造函數。

編輯: 至於您在您的評論問:

person = new User(); 
person.name = "Bob"; 
person.age = 44; 
1

問題#1

prototypemonkey patching利益。如第一個例子所示,該功能是事後添加的。您可以繼續添加或替換您需要的任何方法(儘管公平的警告)。

定義像#2這樣的對象更像是經典的OOP。但是,再次,所有OOP語言都不允許使用猴子修補程序。

問題2

在你的第三個功能,你甚至都不需要getset功能 - nameage是公共屬性(潛在的缺點{})。

var User = { 
    name: "", 
    age: 0 
}; 

User.name = 'Bob'; 
User.age = 44; 

console.log("User: " + User.name + ", Age: " + User.age); 

當您使用{}(對象文本)的對象,{}是構造(不同的瀏覽器)。但是,基本上,不,你不能以這種格式使用構造函數。

4

您的示例#1顯示了prototype屬性的用法。該屬性可用於您創建的所有JavaScript對象,並允許您將屬性或函數添加到對象聲明中,因此您有一個包含2個屬性的對象,稍後添加了4個函數(getter和setter)。

您應該看到原型屬性在運行時修改對象規範的方式,說你有一個名爲名稱的對象:

var Name = { 
    First: "", 
    Last: "" 
}; 

您可以使用原型添加功能getFullName()以後通過簡單地:

Name.prototype.getFullName = function() { return this.First + " " + this.Last; } 

在實施例2將內聯這些getter和setter在對象聲明的聲明所以最終它們是相同的。最後在第三個使用JavaScript對象表示法的例子中,您應該看到JSON

關於你的第二個問題你可以聲明你的對象爲:

var User = { 
    name: "", 
    age: 0 
}; 

這會給你同樣的對象,而getter和setter方法。

12

如果你想在JavaScript中做OOP,我強烈建議查找閉包。我開始在這三個網頁的主題我的學習:

http://www.dustindiaz.com/javascript-private-public-privileged/

http://www.dustindiaz.com/namespace-your-javascript/

http://blog.morrisjohns.com/javascript_closures_for_dummies

之間的區別1,2,和3如下: 1)是向現有對象添加新方法的示例。 2)除了用戶功能中的對象中包含某些方法外,其他與#1相同。 3)是使用JSON定義對象的示例。缺點是你不能使用新的(至少不是這個例子)來定義新對象的實例。但是,您確實可以從便捷的JSON編碼風格中獲益。

如果您還不知道,那麼您一定要閱讀JSON。當你理解JSON時,JavaScript會更有意義。

編輯 如果你想使用的功能#3新,你可以把它寫成

function User() { 
    return { 
    name: "", 
    age: 0, 
    setName: function(name) { 
     this.name = name; 
    }, 
    setAge: function(age) { 
     this.age = age; 
    }, 
    getName: function() { 
     return this.name; 
    }, 
    getAge: function() { 
     return this.age; 
    } 
    }; 
} 

當然,所有這些功能和特性,然後將是公開的。爲了讓他們私密,你需要使用閉包。例如,您可以使用此語法使年齡和名稱保密。

function User() { 
    var age=0; 
    var name=""; 
    return { 
    setName: function(name_) { 
     name = name_; 
    }, 
    setAge: function(age_) { 
     age = age_; 
    }, 
    getName: function() { 
     return name; 
    }, 
    getAge: function() { 
     return age; 
    } 
    }; 
}