JavaScript获取所有属性的getter函数

91

简而言之:我想要一个类似于PHP的getter,但是在JavaScript中实现。

我的JavaScript仅在Firefox中运行,因此仅使用Mozilla特定的JS也可以。

我找到的制作JS getter的唯一方法需要指定其名称,但我想为所有可能的名称定义getter。我不确定这是否可行,但我非常想知道。


7
我想他指的是魔术方法__get和__set。 - seanmonstar
9个回答

126
代理对象可以做到这一点!我很高兴它存在!!这里有一个答案:是否有 JavaScript 等效于 Python 的 __getattr__ 方法? 用我的话来说:

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/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

可在 Chrome、Firefox 和 Node.js 中使用。缺点:不支持 IE - 可恶的 IE。不过很快就会支持。


它在Edge浏览器中也可以工作。请参考caniuse.com获取特定浏览器版本信息。 - styfle
但是如果我想模仿一个函数调用,比如myProxy.foo('bar')。我知道有apply函数可以使用,但是不能使用自定义名称,它总是在代理上执行:myProxy('bar'),我们可以用myProxy('foo','bar')来模仿它,但是这样我们就会失去那种神奇的感觉。 - Enrique
3
如果你从 getter 返回一个函数,那么你绝对可以调用 myProxy.foo('bar') - B T
我认识到这个答案对于问题是正确的,但是对于像我这样想要默认返回值的读者来说,请注意代理优先。 - Barry McNamara
@BarryMcNamara,您能否澄清一下您所说的代理优先级是什么意思? - B T
处理程序捕获对目标对象的调用。如果您的目标具有您希望继续可获取的属性,则需要从处理程序的get方法中显式返回它们。 - Barry McNamara

77

您可以将代理和类组合在一起,使代码看起来像PHP一样美观

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

这个绑定到处理程序,所以你可以使用this代替目标。

注意:与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


6
这是我找到的最佳答案。 - Knight Yoshi
9
这太聪明了。 - Ifnot
在代理中实现“set”以进行赋值操作是不必要的吗? - Enrique
@Enrique 不是的,它的工作方式就像普通对象一样,只不过你可以定义它。 - Ali
简直神奇! - Daniel Node.js

46

你能找到的最接近的是__noSuchMethod____noSuchMethod__已被弃用),它是JavaScript中与PHP的__call()相当的方法。

遗憾的是,没有__get/__set的等效方法,这是令人遗憾的,因为如果有它们,我们就可以实现__noSuchMethod__,但我还没有看到一种使用__noSuchMethod__来实现属性(如C#中所示)的方法。

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

foo.bar(1, 2);

4
“代理”确实是未来的趋势。如果你在Chrome浏览器中启用“about:flags”下的实验性JavaScript功能,就可以使用它了。没有其他与__noSuchMethod__等效的东西。 - Ionuț G. Stan
10
__noSuchMethod__不是标准语法,且任何版本的Internet Explorer都不支持它,因此在许多用户的浏览器上可能无法使用。 - Soroush
2
这个内容的 ECMAScript 相应部分是什么? - vp_arth
8
重要提示:链接现在显示为:“此功能已过时。虽然它仍可能在某些浏览器中工作,但由于它随时可能被移除,因此不建议使用它。请尽量避免使用。” - Wilt
7
虽然__noSuchMethod__已被删除,但ECMAScript 2015(ES6)规范中有Proxy对象,你可以使用它来实现以下内容(以及更多)。 - Albert James Teddy
显示剩余5条评论

5
如果你真的需要一个可行的实现,你可以通过测试第二个参数是否等于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;
        }
    }
};

5

7
不完全是__get()和__set()。PHP的版本允许您监视所有属性,甚至是尚未创建的属性。 - BMiner

1
如果你正在寻找类似于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"
        };
    }
}

0

我最终使用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;
                    };
                }
            })();
        }
    }

0

通过将对象包装在getter函数中,可以轻松地获得类似的结果:

const getProp = (key) => {
  const dictionary = {
    firstName: 'John',
    lastName: 'Doe',
    age: 42,
    DEFAULT: 'there is no prop like this'
  }
  return (typeof dictionary[key] === 'undefined' ? dictionary.DEFAULT : dictionary[key]);
}

console.log(getProp('age')) // 42

console.log(getProp('Hello World')) // 'there is no prop like this'


0

这并不是对原问题的直接回答,但是thisthis的问题已经关闭并转到这里,所以我在这里。我希望我可以像我一样帮助其他JS新手。

来自Python的我想找到的是obj.__getattr__(key)obj.__hasattr__(key)方法的等价物。我最终使用的是:obj[key]代替getattr,以及obj.hasOwnProperty(key)代替hasattrdoc)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接