Как определить сеттер/приемник на прототипе
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?), Я не против, если он не перекрестно совместим.
Ответы
Ответ 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) имеет свое собственное конкретное примитивное значение, которое вычисляется с использованием экземпляра, который его создал.
Конечно, это не так эффективно, как фактическая переменная, потому что каждый экземпляр будет иметь свою собственную копию определенного свойства, но он работает и обеспечивает относительно легкий синтаксис.