2012-09-07 113 views
11

在Javascript中,似乎使用屬性訪問器不是所有常見的(與其他OO語言(例如Java)不同)。javascript屬性訪問器

如果我有一個Person物體的名稱,定義爲

function Person(name) { 
    this.name = name; 
} 

一個人的名字不會改變,但我希望能夠在需要時訪問它,所以我可以做什麼像:

function Person(name) { 
    var name = name; 
    this.getName = function() { 
     return name; 
    } 
} 

即使是在一個動態語言,我想用干將的原則和setter方法應用於他們做靜態類型的面嚮對象語言的相同方式(如封裝,添加驗證,限制出入等)

此問題可能會被視爲主觀,但我很好奇爲什麼這種行爲不會更頻繁地出現(例如,如果一切都公開的話,Java開發人員會變得瘋狂)。

有沒有一個「標準」的方式來做到這一點的JavaScript?我見過Object.defineProperty,但並非所有的瀏覽器都支持這一點。

+0

我假設它可能部分與降低帶寬負載的願望有關。額外的標記意味着穿過電線的額外位。雖然在這樣一個小例子的情況下,它可能看起來並不相關,但在一個跨越數萬行的強大應用程序中,它可能會變得很重要。 – Shmiddty

+0

額外的定義也意味着客戶端上的額外內存使用量,與我之前的評論相同。 – Shmiddty

+0

我想已經給出的答案表明,這不是一個好的問題,因爲它很容易得到基於意見的答案。 – madth3

回答

15

JavaScript有攔截,能夠屬性訪問:

http://ejohn.org/blog/javascript-getters-and-setters/

恕我直言,這是一個更好的解決方案來執行比Java的更嚴格明確的干將統一接入的原則,但也是簡單的一部分,該語言不靈活(例如Groovy允許類似的截取)。

+0

在實踐中,這看到很多?或者通常你看到直接財產訪問? –

+0

除非需要修改訪問者邏輯,否則您將使用直接屬性訪問權限,那麼您將使用攔截功能。如果你沒有做任何事情,你可能需要問自己:爲什麼你用Java中的getter和setter:封裝原則背後的實際原因是什麼? –

+0

有時我會問自己爲什麼,特別是簡單的屬性。理論上這個想法是,如果你想在getter或setter中添加一些其他行爲(例如日誌記錄,驗證等)。但實際上,這並不是簡單的屬性上經常發生的事情,所以它更像是一個Java約定(我更喜歡groovy是如何在沒有明確聲明getter和setter的地方進行的,但它們是生成並自動調用的,但允許您編寫直屬性訪問的語法)。 –

3

我認爲答案是在javascript中模擬類不是常見的做法,因爲該語言實際上是原型的。

儘管可以創建類結構(如你的例子),但它們並不是真的像java類,而作爲一名程序員,你最終會與細微之處發生衝突。

但是,如果您擁抱javascript的原型性質,那麼您將得到一種不同的,但內聚性強且結構簡單的語言獎勵。

沒有必要使用具有原型結構的getter和setter,因爲您可以簡單地設置一個對象,並將其設置爲一個值,然後將其作爲值調用。

JavaScript不會強制您編寫結構化代碼,也不會阻止您這樣做。我認爲,圍繞javascript發展起來的文化已經開發出了一種很好的編碼風格,這是完全有效的,與我使用的其他語言不同。

我知道這個答案不是確定性的,也是確鑿的,但希望有一些想法可以幫助你找到你正在尋找的anser。

+1

謝謝。你可以直接在java中執行相同的get/set值(如果你公開的東西是公開的),但是這似乎被忽略了。我想這很大程度上與這個語言的成語有什麼關係。 –

+1

Java中的一個主要問題是您不希望稍後改變類的接口。作爲一種爲長期代碼維護而設計的編譯語言,優先級與JS--一種在快速變化的Web環境中部署的基於源代碼的語言不同。 –

7

我知道我對這個問題的想法。

吸氣劑和安裝劑是邪惡的。

等等!真!忍受我一會兒,讓我解釋一下。

只是使用一種方法來獲取和設置一個值是..好..有點毫無意義。它不保護,不是真的,你放入的是你得到的東西。

另一方面,我非常喜歡將信息放入信息的方法,然後再獲取信息。但這裏是魔法部分!這不是同一個信息。不直接。

function Person(name) { 
    this.getFullName = function() {return this.firstName + " " + this.lastName;}; 
    this.setBirthday = function(date) { this.birthday = date; }; 

    this.getAge = function() { /* Return age based on the birthday */ }; 
    this.isOfLegalDrinkingAge function() { /* do your math here too */ }; 
} 

但大多數時候我只是推動靜態數據並獲取靜態數據。把它藏在吸氣劑和吸附劑後面有什麼意義?

作爲一個次要的原因,處理DOM和大多數主機對象,你設置屬性。你不玩弄吸氣和安裝者。不使用它們適合JS編碼器所做的其他「風格」。

+0

@BillyMoon - 奇蹟,如果他可以更改他的用戶名到「Javascript傳教者」 –

+0

感謝您的解釋。我認爲這不是JavaScript的「味道」,這實際上是我在這裏得到的。 –

+0

我的問題是想知道事情是功能還是屬性。有時它看起來很隨意。 Person.firstName工程,但Person.firstName()並不相反,我需要使用Person.fullName()而不是Person.fullName ... – CuddleBunny

0

我道歉,如果我不理解正確的問題,而是自我執行功能是使成員公共單程/私人

var Person = function(){ 
    var _name = "Roger", 
     self = { getName : function(){ return _name; }}; 
    return self; 
}() 

然後,您可以從任何地方訪問Person.getName(),但不能設置_name 。

+1

我知道你可以做到這一點,它似乎不是很常見的做法... –

1

這是我用於本地字段:

TYPE_DEFAULT_VALUE= { 
    number: 0, 
    string: "", 
    array: [], 
    object: {}, 
}; 

typeOf = function (object) { 
    if (typeof object === "number" && isNaN(object)) 
     return NaN; 
    try { 
     return Object.prototype.toString.call(object).slice(8, -1).toLowerCase(); 
    } 
    catch(ex) { 
     return "N/A"; 
    }; 
}; 

getAccessor = function(obj, key, type, defaultValue) { 
    if (defaultValue === undefined) 
     defaultValue = TYPE_DEFAULT_VALUE[type] === undefined ? null : TYPE_DEFAULT_VALUE[type]; 
    return { 
     enumerable: true, 
     configurable: true, 
     get: function() { 
      if (obj[key] === undefined) 
       obj[key] = defaultValue; 
      return obj[key]; 
     }, 
     set: function (value) { 
      if (typeOf(value) === type) 
       obj[key] = value; 
     }, 
    }; 
} 

LocalFields = function (fields, object) { 
    /** 
    * field properties 
    * { 
    * type: [ required ] (number | string | array | object | ...), 
    * defaultValue: [ optional ] 
    * } 
    */ 
    if (! fields) 
     throw "Too few parameters ..."; 
    if (! object) 
     object = this; 

    var obj = this; 
    var fieldsAccessor = {}; 
    for(key in fields){ 
     field = fields[key]; 
     fieldHandler = key[0].toUpperCase() + key.substr(1); 
     if(! field.type) 
      throw "Type not set for field: " + key; 

     fieldsAccessor[fieldHandler] = getAccessor(obj, fieldHandler, field.type, field.defaultValue) 
    } 
    Object.defineProperties(object, fieldsAccessor); 
} 

現在,每一個類,我可以只需要調用是這樣的:

Person = function(){ 
    new LocalFields({ 
     id:  { type: "number" }, 
     name: { type: "string" }, 
    }, this); 
} 

然後像VS getter和setter你撥打:

var alex = new Person(); 
alex.Name = "Alex Ramsi"; 
console.clear(); 
console.info(alex.Name);