Как определить сеттер / геттер по прототипу

EDIT Oct 2016Обратите внимание, что этот вопрос был задан в 2012 году. Каждый месяц или около того кто-то добавляет новый ответ или комментарий, который опровергает ответ, но на самом деле это не имеет смысла, поскольку вопрос, вероятно, устарел (помните, что это было дляGnome Javascript писать расширения оболочки gnome, а не вещи браузера, что довольно специфично).

Следующиймой предыдущий вопрос о том, как сделать подклассы в Javascript, я делаю подкласс суперкласса так:

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.

Мой вопросhow do I define a setter/getter on the prototype with this syntax?

Обычно я делал:

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

    get myProperty() {
        // code.
    }
}

Но очевидно, что следующее не сработает:

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

Я использую GJS (GNOME Javascript), и предполагается, что этот движок более или менее такой же, как и Mozilla Spidermonkey. Мой код не предназначен для браузера, поэтому, пока он поддерживается GJS (я полагаю, что это означает Spidermonkey?), Я не возражаю, если он не является кросс-совместимым.

 mathematical.coffee15 мая 2012 г., 02:38
Фантастика, это похоже на то, что я ищу. Если вы отправите это как ответ, я приму это. ура! :)
 bfavaretto15 мая 2012 г., 02:35
Мозилла упоминает документы__defineGetter__ а также__defineSetter (но я никогда не использовал их ...). Developer.mozilla.org / о / Core_JavaScript_1.5_Guide / ...
 Hal5000002 окт. 2016 г., 20:34
Пожалуйста, не делай этого. Наследование в JS состоит из трех строк: вызов суперкласса, установка прототипа в суперкласс и сброс конструктора обратно в дочерний класс. Конец. Написание таких методов - пустая трата времени.
 bfavaretto15 мая 2012 г., 02:41
Сделайте это и добавьте примеры из MDN.

Ответы на вопрос(5)

function Unit() {
   	this._data; // just temp value
}
Unit.prototype = {
 	get accreation() {
   		return this._data;
   	},
   	set accreation(value) {
   		this._data = value
   	},
}
Unit.prototype.edit = function(data) {
   	this.accreation = data; // setting
   	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
   	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

 Hal5000028 янв. 2017 г., 23:01
@ faintsignal На самом деле, чтобы исправить себя, есть несколько причин использоватьObject.defineProperty() вместо приведенного выше примера, когда вы хотите установить перечислимое, настраиваемое, доступное для записи и т. д. Но вы правы, взглянуть на дату публикации - хорошая идея.
 faintsignal12 янв. 2017 г., 21:23
@ Hal50000 Вы игнорируете, что этот ответ был опубликован почти через 4 года после того, как вопрос был задан.
 jonS9029 янв. 2017 г., 18:00
Unit.prototype.constructor стирается при перезаписиUnit.prototype так. Мне очень нравится это решение, хотя. Может быть, вы могли бы сделатьObject.assign(Unit.prototype, { get accreation() { ... } });.
 Hal5000002 окт. 2016 г., 20:33
Удивительно. Единственно правильный ответ не получает голосов. Существует НОЛЬ причина использоватьObject.defineProperty если тебе не придется терпеть оскорбление старого IE.
 cmroanirgo28 дек. 2017 г., 06:51
as @ jonS90 упоминает, что есть некоторыеочен веские причины, почему этот метод может быть плохой идеей. Вы теряете наследование классов и т. Д. Было бы лучше использовать альтернативные методы, если вы используете иерархию классов. например, выне могу наделить собственностьField используя этот метод.

Object.defineProperty (). Этот метод принимает три аргумента: первый аргумент - это объект, к которому добавляется свойство, второй - имя свойства, а третий - дескриптор свойства. Например, мы можем определить конструктор для нашего объекта person следующим образом:

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;
}());

Using Object.defineProperty () дает больше контроля над определением нашего свойства. Например, мы можем указать, может ли описываемое нами свойство динамически удаляться или переопределяться, может ли быть изменено его значение и т.

Мы можем создать такие ограничения, задав следующие свойства объекта дескриптора:

writable: это логическое значение, которое указывает, можно ли изменить значение свойства; значение по умолчанию - falseconfigurable: это логическое значение, которое указывает, можно ли изменить дескриптор свойства или удалить само свойство; значение по умолчанию - falseenumerable: это логическое значение, указывающее, можно ли получить доступ к свойству в цикле над свойствами объекта; значение по умолчанию - falsevalue: представляет значение, связанное со свойством; его значение по умолчанию не определено
Решение Вопроса

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__ ( РЕКОМЕНДУЕТСЯ):

var d = Date.prototype;
d.__defineGetter__("year", function() { return this.getFullYear(); });
d.__defineSetter__("year", function(y) { this.setFullYear(y); });
 bfavaretto19 июн. 2015 г., 22:32
@ royhowie Я вижу, ES5get/ setинтаксис @, кажется, вдохновил новый синтаксис метода:)
 royhowie19 июн. 2015 г., 22:03
Извините моя ошибка. Я неправильно понял это для новой функции, введенной в es6:let foo = { bar () { return baz }}
 StanE27 февр. 2016 г., 00:08
Я не думаю, что нужно снова писать имя функции для получателя. Примеры документов MDN используют анонимные функции.
 grabantot13 июн. 2017 г., 12:10
Также будьте осторожны с лямбдами в методах получения / установки.this в лямбдах относится к глобальному объекту.

ИспользуйтеObject.defineProperty() наSubclass.prototype. Это также__defineGetter__ а также__defineSetter__ доступно в некоторых браузерах, но не рекомендуется. Для вашего примера это будет:

Object.defineProperty(Subclass.prototype, "myProperty", {
    get: function myProperty() {
        // code
    }
});
 Fabrício Matté28 апр. 2013 г., 00:46
"они устарели (так же, как__proto__)" - Обратите внимание, что__proto__ стандартизируется с версии ES6.
 Fabrício Matté28 апр. 2013 г., 01:04
Да, я просто добавил примечание, что оно не будет считаться устаревшим, когда ES6 станет стандартом (даже утечка для IE11, по-видимому, уже реализована). Хотя, конечно, у нас есть много времени, прежде чем мы сможем подумать об использовании его в реальной среде, для тех немногих вариантов использования, которые могут иметь место.
 Bergi18 окт. 2015 г., 15:46
@ bob Не уверен, что ваш комментарий должен означать. Конечно, если вы хотите получить продолжительность динамически, вам понадобится геттер, но он может работать с другими свойствами так же, как и все другие методы:Object.defineProperty(…, "duration", { get: function() { return this.end - this.begin; }});
 Bergi28 апр. 2013 г., 01:01
@ FabrícioMatté: я знаю (но мне это не нравится). Тем не менее, смысл в том, чтобы использоватьObject.create вместо.
 Johann24 апр. 2015 г., 22:15
Duh! «Как определить сеттер / геттер [свойство] в прототипе?» «Вы определяете его как свойство прототипа.»

вы должны сделать что-то вроде этого:

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

Вы можете сократить это с помощью функции полезности:

//creates get/set properties inside an object's proto
function prop (propname, getfn, setfn) {
    var obj = {};
    obj[propname] = { get: getfn, set: setfn };
    Object.defineProperties(this, obj);        
}

function Product () {
     this.name =  "Product";
     this.amount =  10;
     this.price =  1;
     this.discount =  0;
}

//how to use prop function
prop.apply(Product.prototype, ["total", function(){ return this.amount * this.price}]);

pr = new Product();
console.log(pr.total);

Здесь мы используем prop.apply, чтобы задать контекст Product.prototype как «this», когда мы его называем.

С этим кодом у вас заканчивается свойство get / set внутри прототипа объекта, а не экземпляра, как задан вопрос.

(Протестировано Firefox 42, Chrome 45)

 faintsignal12 янв. 2017 г., 21:36
Очень хорошо. Хотя вы не применили сеттер в своем примере, поэтому пытаетесь установитьpr.total молча провалится. На практике, вероятно, лучше всего передать функцию установки, чтобы выдать ошибку, когда нужно только создать метод получения.

Ваш ответ на вопрос