Обновление 2013 и 2015 гг. (См. Ниже исходный ответ от 2011 г.) :
Это изменилось в спецификации ES2015 (также известной как «ES6»): теперь у JavaScript есть прокси . Прокси-серверы позволяют создавать объекты, которые являются настоящими заместителями (фасадами) других объектов. Вот простой пример, который при извлечении переводит все значения свойств, которые являются строками, заглавными буквами:
"use strict";
if (typeof Proxy == "undefined") {
throw new Error("This browser doesn't support Proxy");
}
let original = {
"foo": "bar"
};
let proxy = new Proxy(original, {
get(target, name, receiver) {
let rv = Reflect.get(target, name, receiver);
if (typeof rv === "string") {
rv = rv.toUpperCase();
}
return rv;
}
});
console.log(`original.foo = ${original.foo}`); // "original.foo = bar"
console.log(`proxy.foo = ${proxy.foo}`); // "proxy.foo = BAR"
Операции, которые вы не отменяете, имеют поведение по умолчанию. Все, что мы переопределяем выше, есть get
, но есть целый список операций, к которым вы можете подключиться.
В get
списке аргументов функции-обработчика:
target
проксируемый объект ( original
в нашем случае).
name
- это (конечно) имя извлекаемого свойства, которое обычно является строкой, но также может быть символом.
receiver
- это объект, который следует использовать, как this
в функции получения, если свойство является средством доступа, а не свойством данных. В обычном случае это прокси или что-то, что от него наследуется, но это может быть что угодно, поскольку ловушка может быть вызвана Reflect.get
.
Это позволяет вам создать объект с желаемой функцией универсального получения и установки:
"use strict";
if (typeof Proxy == "undefined") {
throw new Error("This browser doesn't support Proxy");
}
let obj = new Proxy({}, {
get(target, name, receiver) {
if (!Reflect.has(target, name)) {
console.log("Getting non-existent property '" + name + "'");
return undefined;
}
return Reflect.get(target, name, receiver);
},
set(target, name, value, receiver) {
if (!Reflect.has(target, name)) {
console.log(`Setting non-existent property '${name}', initial value: ${value}`);
}
return Reflect.set(target, name, value, receiver);
}
});
console.log(`[before] obj.foo = ${obj.foo}`);
obj.foo = "bar";
console.log(`[after] obj.foo = ${obj.foo}`);
Результат вышеизложенного:
Получение несуществующего свойства 'foo'
[до] obj.foo = undefined
Установка несуществующего свойства 'foo', начальное значение: bar
[после] obj.foo = bar
Обратите внимание на то, как мы получаем сообщение «несуществующее», когда пытаемся извлечь, foo
когда оно еще не существует, и снова, когда мы его создаем, но не после этого.
Ответ от 2011 года (см. Выше обновления за 2013 и 2015 годы) :
Нет, в JavaScript нет универсальной функции свойств. Синтаксис средства доступа, который вы используете, описан в Разделе 11.1.5 спецификации и не предлагает подстановочных знаков или чего-то подобного.
Вы, конечно, можете реализовать функцию для этого, но я предполагаю, что вы, вероятно, не хотите использовать f = obj.prop("foo");
вместо f = obj.foo;
и obj.prop("foo", value);
вместо obj.foo = value;
(что было бы необходимо для функции для обработки неизвестных свойств).
FWIW, функция получения (я не заморачивался с логикой установки) будет выглядеть примерно так:
MyObject.prototype.prop = function(propName) {
if (propName in this) {
// This object or its prototype already has this property,
// return the existing value.
return this[propName];
}
// ...Catch-all, deal with undefined property here...
};
Но опять же, я не могу представить, что вы действительно захотите это сделать, потому что это меняет способ использования объекта.