2012-05-15 34 views
64

編輯2016年10月:請注意這個問題在2012年被問到。每個月左右有人添加一個新的答案或評論來駁斥答案,但並沒有真正意義這樣做的問題可能已過時(請記住,它是用於編寫gnome-shell擴展的,而不是瀏覽器的東西,這非常具體),用於Gnome Javascript如何在原型上定義setter/getter

下面就如何在Javascript中做子類my previous question,我正在做一個超類的子類,像這樣:

function inherits(Child,Parent) { 
    var Tmp = function {}; 
    Tmp.prototype = Parent.prototype; 
    Child.prototype = new Tmp(); 
    Child.prototype.constructor = Child; 
} 
/* Define subclass */ 
function Subclass() { 
    Superclass.apply(this,arguments); 
    /* other initialisation */ 
} 
/* Set up inheritance */ 
inherits(Subclass,Superclass); 
/* Add other methods */ 
Subclass.prototype.method1 = function ... // and so on. 

我的問題是,我怎麼定義的原型,一個setter /吸氣這個語法?

我以前做的:

Subclass.prototype = { 
    __proto__: Superclass.prototype, 
    /* other methods here ... */ 

    get myProperty() { 
     // code. 
    } 
} 

但顯然以下將不起作用:

Subclass.prototype.get myProperty() { /* code */ } 

我使用GJS(GNOME的Javascript),發動機,就是要與Mozilla Spidermonkey相同或多或少。我的代碼不適用於瀏覽器,只要它支持GJS(我猜這意味着Spidermonkey?),我不介意它是不是交叉兼容的。

+0

Mozilla文檔提到'__defineGetter__'和'__defineSetter'(但我從來沒有真正使用過那些...)。 https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Working_with_Objects#Defining_getters_and_setters – bfavaretto

+0

非常棒,這看起來像我之後。如果您將它作爲答案發布,我會接受它。乾杯! :) –

+0

做到了這一點,並添加了來自MDN的示例。 – bfavaretto

回答

56

使用對象文本聲明(簡單的方法):

var o = { 
    a: 7, 
    get b() { 
     return this.a + 1; 
    }, 
    set c(x) { 
     this.a = x/2 
    } 
}; 

使用Object.defineProperty(現代瀏覽器都支持ES5):

Object.defineProperty(o, "myProperty", { 
    get: function myProperty() { 
     // code 
    } 
}); 

或者使用__defineGetter____defineSetter__DEPRECATED):

var d = Date.prototype; 
d.__defineGetter__("year", function() { return this.getFullYear(); }); 
d.__defineSetter__("year", function(y) { this.setFullYear(y); }); 
+0

對不起,我的錯。我誤解了es6中引入的新函數符號:'let foo = {bar(){return baz}}' – royhowie

+0

@royhowie我看到,ES5'get' /'set'語法似乎激發了新的方法語法:) – bfavaretto

+0

我不認爲有必要再次爲getter寫一個函數名。 MDN實例使用匿名函數。 – StanE

81

Subclass.prototype上使用Object.defineProperty()。在某些瀏覽器上也有__defineGetter____defineSetter__,但它們已被棄用。對於你的榜樣,那就是:

Object.defineProperty(Subclass.prototype, "myProperty", { 
    get: function myProperty() { 
     // code 
    } 
}); 
+1

「它們已被棄用(就像'__proto__')」 - 注意'__proto__'在ES6草案中被標準化。 –

+0

@FabrícioMatté:我知道(但我不喜歡它)。但是,這裏的重點是使用Object.create而不是。 – Bergi

+0

是的,我剛剛添加了一個說明,一旦ES6成爲標準(甚至IE11的泄漏顯然已經實現),它將不會被視爲棄用。雖然當然,有很長一段時間我們可以考慮在真實環境中使用它,因爲它可能有少數用例。 –

3

要定義「對象的原型裏面的」 getter和setter方法,你必須做這樣的事情:

Object.defineProperties(obj.__proto__, {"property_name": {get: getfn, set: setfn}}) 

您可以做空下來與效用函數:

這裏當我們調用它時,我們使用prop.apply將上下文Product.prototype設置爲「this」。

通過此代碼,您可以在對象的原型中獲取get/set屬性,而不是實例,如問題所述。

(測試火狐42,鉻45)

+0

非常好。雖然,你沒有在你的例子中應用setter,所以試圖設置'pr.total'會失敗。在實踐中,當只想創建一個getter時,最好傳遞一個setter函數來拋出錯誤。 – faintsignal

25

我想你想做的事是這樣的:

function Unit() { 
 
    \t this._data; // just temp value 
 
} 
 
Unit.prototype = { 
 
    \t get accreation() { 
 
    \t \t return this._data; 
 
    \t }, 
 
    \t set accreation(value) { 
 
    \t \t this._data = value 
 
    \t }, 
 
} 
 
Unit.prototype.edit = function(data) { 
 
    \t this.accreation = data; // setting 
 
    \t this.out(); 
 
}; 
 

 
Unit.prototype.out = function() { 
 
    alert(this.accreation); // getting 
 
}; 
 

 
var unit = new Unit(); 
 
unit.edit('setting and getting'); 
 

 
function Field() { 
 
    // children 
 
} 
 

 
Field.prototype = Object.create(Unit.prototype); 
 

 
Field.prototype.add = function(data) { 
 
    this.accreation = data; // setting 
 
    \t this.out(); 
 
} 
 

 
var field1 = new Field(); 
 
field1.add('new value for getter&setter'); 
 

 
var field2 = new Field(); 
 
field2.out();// because field2 object has no setting

+2

令人驚歎。唯一正確的答案是沒有投票。除非你必須遭受舊IE的侮辱,否則有零的理由使用'Object.defineProperty'。 – Hal50000

+1

@ Hal50000你忽略了這個答案在提出問題近4年後發佈。 – faintsignal

+1

@faintsignal其實,爲了糾正自己,當你想設置可枚舉,可配置,可寫等等時,有一些原因使用Object.defineProperty()而不是上面的例子。但是你是對的,看看該帖子的日期是一個好主意。 – Hal50000

3

指定一個get在構造函數中使用Object.defineProperty()方法創建或設置setter。 此方法有三個參數:第一個參數 是要添加屬性的對象,第二個參數是屬性的名稱,第三個參數是屬性的描述符。例如,我們可以定義構造函數爲我們 人對象如下:

var Employee = (function() { 
    function EmployeeConstructor() { 
     this.first = ""; 
     this.last = ""; 
     Object.defineProperty(
      this, 
      "fullName", { 
       get: function() { 
        return this.first + " " + 
         this.last; 
       }, 
       set: function(value) { 
        var parts = value.toString().split(" "); 
        this.name = parts[0] || ""; 
        this.last = parts[1] || ""; 
       } 
      }); 
    } 
    return 
    EmployeeConstructor; 
}()); 

使用Object.defineProperty()給出了我們的財產定義 更多的控制。例如,我們可以指定我們 正在描述的屬性是否可以動態刪除或重新定義,如果它的值可以更改等等 。

我們可以這樣的約束通過設置描述符對象的以下屬性:

  • 可寫:這是一個布爾值,表示所述 屬性值是否可以被改變;它的默認值是假
  • 配置:這是一個布爾值,表示該屬性的 描述是否可以更改或物業本身可以被刪除;其 默認值爲假
  • enumerable:這是一個布爾值,指示屬性是否可以在對象的屬性中以循環訪問屬性 ;其默認值爲 false
  • value:這表示與該屬性關聯的值;它的 默認值是undefined
相關問題