JavaScript getter для всех свойств

Короче говоря: я в ситуации, когда мне нужен геттер в стиле PHP, но в JavaScript.

Мой JavaScript работает только в Firefox, поэтому Mozilla специфический JS в порядке.

Единственный способ, которым я могу найти, чтобы получить JS getter, требует указания его имени, но я бы хотел определить getter для всех возможных имен. Я не уверен, что это возможно, но я очень хотел бы знать.

Ответ 1

Ближе всего вы можете найти __ noSuchMethod__, который является эквивалентом JavaScript PHP __call().

К сожалению, нет эквивалента __get/__ set, что является позором, потому что с ними мы могли бы реализовать __noSuchMethod__, но я пока не вижу способа реализовать свойства (как на С#) с помощью __noSuchMethod __.

var foo = {
    __noSuchMethod__ : function(id, args) {
        alert(id);
        alert(args);
    }
};

foo.bar(1, 2);

Ответ 2

Proxy может это сделать! Я так счастлив, что это существует! Ответ приведен ниже: Есть ли эквивалент javascript метода __getattr__ python?. Перефразировать мои собственные слова:

var x = new Proxy({},{get(target,name) {
  return "Its hilarious you think I have "+name
}})

console.log(x.hair) // logs: "Its hilarious you think I have hair"

Прокси для победы! Ознакомьтесь с документами MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

Работает в chrome, firefox и node.js. Недостатки: не работает в IE - freakin IE. Скоро.

Ответ 3

Если вы кодируете в ES6, вы можете комбинировать прокси и класс, чтобы иметь красивый код, например php:

class Magic {
    constructor () {
        return new Proxy(this, this);
    }
    get (target, prop) {
        return this[prop] || 'MAGIC';
    }
}

это привязывается к обработчику, поэтому вы можете использовать его вместо целевого.

Примечание: в отличие от PHP прокси обрабатывает весь запрос свойства.

let magic = new Magic();
magic.foo = 'NOT MAGIC';
console.log(magic.foo); // NOT MAGIC
console.log(magic.bar); // MAGIC

Вы можете проверить, какие браузеры поддерживают прокси http://caniuse.com/#feat=proxy и класс http://caniuse.com/#feat=es6-class. Node 8 поддерживают оба.

Ответ 4

Javascript 1.5 имеет getter/setter синтаксический сахар. Он очень хорошо объяснил Джон Ресиг здесь

Это не достаточно общее для использования в Интернете, но, безусловно, Firefox имеет их (также Rhino, если вы когда-либо захотите использовать его на стороне сервера).

Ответ 5

Если вам действительно нужна реализация, которая работает, вы можете "обманывать" свой путь arround, проверяя второй параметр на undefined, это также означает, что вы можете использовать get для фактического задания параметра.

var foo = {
    args: {},

    __noSuchMethod__ : function(id, args) {
        if(args === undefined) {
            return this.args[id] === undefined ? this[id] : this.args[id]
        }

        if(this[id] === undefined) {
            this.args[id] = args;
        } else {
            this[id] = args;
        }
    }
};

Ответ 6

Если вы ищете что-то вроде PHP __get(), я не думаю, что Javascript предоставляет любую такую ​​конструкцию.

Лучшее, что я могу думать о том, чтобы сделать, - это цикл через объект-не-функциональный элемент, а затем создание соответствующей функции "getXYZ()" для каждого.

В изворотливом псевдо-иском коде:

for (o in this) {
    if (this.hasOwnProperty(o)) {
        this['get_' + o] = function() {
            // return this.o -- but you'll need to create a closure to
            // keep the correct reference to "o"
        };
    }
}

Ответ 7

В итоге я использовал ответ nickfs для создания собственного решения. Мое решение автоматически создаст функции get_ {propname} и set_ {propname} для всех свойств. Он проверяет, существует ли функция перед их добавлением. Это позволяет переопределить метод get или set по умолчанию с нашей собственной реализацией без риска перезаписывания.

for (o in this) {
        if (this.hasOwnProperty(o)) {
            var creategetter = (typeof this['get_' + o] !== 'function');
            var createsetter = (typeof this['set_' + o] !== 'function');
            (function () {
                var propname = o;
                if (creategetter) {
                    self['get_' + propname] = function () {
                        return self[propname];
                    };
                }
                if (createsetter) {
                    self['set_' + propname] = function (val) {
                        self[propname] = val;
                    };
                }
            })();
        }
    }