Подтвердить что ты не робот

Как определить сеттер/приемник на прототипе

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

Следуя моему предыдущему вопросу о том, как сделать подкласс в 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.

Мой вопрос: как определить setter/getter на прототипе с этим синтаксисом?

Я использовал:

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

    get myProperty() {
        // code.
    }
}

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

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

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

4b9b3361

Ответ 1

Использование объявления литерала объекта (простейший способ):

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

Ответ 2

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

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

Ответ 3

Я думаю, вы хотели сделать так:

Ответ 4

Чтобы определить сеттеры и геттеры "внутри прототипа объекта", вы должны сделать что-то вроде этого:

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

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

//creates get/set properties inside an object 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)

Ответ 5

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

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() дает больше контроля над нашим определением собственности. Например, мы можем указать, обладает ли свойство могут быть динамически удалены или переопределены, если его значение можно изменить, и поэтому на.

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

  • writeable: это логическое значение, указывающее, будет ли значение свойство может быть изменено; его значение по умолчанию - false
  • configurable: это логическое значение, указывающее, является ли свойство дескриптор может быть изменен или само свойство может быть удалено; его значение по умолчанию - false
  • enumerable: это логическое значение, указывающее, может ли это свойство доступ в цикле по свойствам объекта; его значением по умолчанию является ложь
  • value: представляет значение, связанное с этим свойством; его значение по умолчанию undefined

Ответ 6

Когда я пишу это, Internet Explorer, похоже, имеет ограниченную поддержку defineProperties для произвольных протоколов, поэтому я попытался реализовать установщик без его использования.

Я все еще ищу что-то подобное для сеттера, но здесь идет...

function Property(instance,getValue) 
{ 
  this.instance = instance;
  this.getValue = getValue 
}
Property.prototype.valueOf = function() 
{ return this.getValue.call(this.instance) }
Property.prototype.toString = function()
{ return "" + this.valueOf() }

MyObject = function(iv) 
{
   this.internalValue = iv;
   this.worldly = new Property(this,function(){ return this.internalValue +  " world"})
   this.saying = new Property(this,function(){ return "Just saying " + this.internalValue})
}

var obj = new MyObject("Hello");

alert(obj.worldly) // "Hello world"

obj.internalValue = "Goodbye";

alert(obj.worldly); // "Goodbye world"
alert(obj.saying);  // "Just saying Goodbye"

При этом используется возможность определять примитивное значение для объекта с помощью функции valueOf(). Создавая переменную внутри объекта, который является экземпляром Property, возвращаемое значение (Property) имеет свое собственное конкретное примитивное значение, которое вычисляется с использованием экземпляра, который его создал.

Конечно, это не так эффективно, как фактическая переменная, потому что каждый экземпляр будет иметь свою собственную копию определенного свойства, но он работает и обеспечивает относительно легкий синтаксис.