Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/73.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
可以在JavaScript中实现动态getter/setter吗?_Javascript_Metaprogramming_Getter Setter - Fatal编程技术网

可以在JavaScript中实现动态getter/setter吗?

可以在JavaScript中实现动态getter/setter吗?,javascript,metaprogramming,getter-setter,Javascript,Metaprogramming,Getter Setter,我知道如何通过以下操作为已经知道名称的属性创建getter和setter: // A trivial example: function MyObject(val){ this.count = 0; this.value = val; } MyObject.prototype = { get value(){ return this.count < 2 ? "Go away" : this._value; }, set value(v

我知道如何通过以下操作为已经知道名称的属性创建getter和setter:

// A trivial example:
function MyObject(val){
    this.count = 0;
    this.value = val;
}
MyObject.prototype = {
    get value(){
        return this.count < 2 ? "Go away" : this._value;
    },
    set value(val){
        this._value = val + (++this.count);
    }
};
var a = new MyObject('foo');

alert(a.value); // --> "Go away"
a.value = 'bar';
alert(a.value); // --> "bar2"
//一个简单的例子:
函数MyObject(val){
此值为0.count;
this.value=val;
}
MyObject.prototype={
获取值(){
返回this.count<2“走开”:this.\u值;
},
设定值(val){
此._值=val+(++this.count);
}
};
变量a=新的MyObject(“foo”);
警报(a.值);//-->“走开”
a、 值='bar';
警报(a.值);//-->“bar2”
现在,我的问题是,有没有可能像这样定义一种“一网打尽”的接受者和接受者?即,为任何尚未定义的属性名创建getter和setter

这个概念在PHP中可以使用
\uuuu get()
\uuu set()
魔术方法(有关这些方法的信息,请参阅),所以我真的想问,是否有一个JavaScript与这些方法等效


不用说,我最希望的解决方案是跨浏览器兼容。

2013年和2015年更新版(2011年的原始答案见下文):

这在ES2015(又称“ES6”)规范中有所改变:JavaScript现在已经有了。通过代理,可以创建其他对象(立面上)的真实代理对象。下面是一个简单的示例,用于在检索时将任何字符串属性值转换为所有大写:

“严格使用”;
如果(代理类型==“未定义”){
抛出新错误(“此浏览器不支持代理”);
}
让原件={
“foo”:“bar”
};
让代理=新代理(原始{
获取(目标、名称、接收者){
让rv=Reflect.get(目标、名称、接收者);
if(rv类型==“字符串”){
rv=rv.toUpperCase();
}
返回rv;
}
});
console.log(`original.foo=${original.foo}`);//“original.foo=bar”
console.log(`proxy.foo=${proxy.foo}`);//“proxy.foo=BAR”

这对我很有效

以下可能是解决此问题的原始方法:

var obj = {
  emptyValue: null,
  get: function(prop){
    if(typeof this[prop] == "undefined")
        return this.emptyValue;
    else
        return this[prop];
  },
  set: function(prop,value){
    this[prop] = value;
  }
}
为了使用它,属性应该作为字符串传递。 下面是一个如何工作的示例:

//To set a property
obj.set('myProperty','myValue');

//To get a property
var myVar = obj.get('myProperty');
编辑: 基于我提出的改进的、更面向对象的方法如下:

function MyObject() {
    var emptyValue = null;
    var obj = {};
    this.get = function(prop){
        return (typeof obj[prop] == "undefined") ? emptyValue : obj[prop];
    };
    this.set = function(prop,value){
        obj[prop] = value;
    };
}

var newObj = new MyObject();
newObj.set('myProperty','MyValue');
alert(newObj.get('myProperty'));

你可以看到它在工作。

前言:

提到了一个
代理
,对于OP所要求的不存在的属性,这将是catch-all getter/setter所需要的。根据动态getter/setter实际需要的行为,实际上可能不需要
代理
;或者,您可能希望将
代理
与我将在下面向您展示的内容结合使用

(另一方面,我最近在Linux上的Firefox中彻底试验了
代理
,发现它非常有能力,但也有点令人困惑/难以使用和正确使用。更重要的是,我还发现它相当慢(至少就目前JavaScript的优化程度而言)-我说的是deca倍增速度较慢的领域。)


要具体实现动态创建的getter和setter,可以使用或。这也相当快

要点是您可以在对象上定义getter和/或setter,如下所示:

让obj={};
设val=0;

Object.defineProperty(obj,'prop',{//我设法做到了,请参阅了解如何使用
Function()
这就像使用
eval
。直接将函数作为
defineProperty
的参数。或者,如果出于某种原因,您坚持动态创建
get
set
,则使用一个高阶函数创建函数并返回它,如
var get=(函数(propName){return function(){return this[propName];};}('value');
这不起作用。如果不指定属性的名称,就不能定义getter。@JohnKurlak检查这个jsFiddle:它起作用。您只需将属性名称作为字符串传递。啊,感谢您的澄清。我以为您在尝试使用get()/set()语言功能,而不是编写自己的get()/set()。但我仍然不喜欢这个解决方案,因为它并不能真正解决原始问题。@JohnKurlak嗯,我写的是一个原始方法。它提供了一种不同的方法来解决问题,即使它不能解决现有代码使用更传统方法的问题。但如果您从scratch.当然不值得投反对票…@JohnKurlak看看现在是否看起来更好了!:)有一个替代
Proxy
Object.defineProperty()
。我把细节放在了我的新文件中。@Andrew-恐怕你误读了这个问题,请看我对你答案的评论。注意:在IE11中,Proxy本机不可用(截至2020年,一些公司支持它的时间比max多了5年)。polyfill+babel可能存在。或者您可能希望使用Object.defineProperty返回ES5版本。恐怕您误读了这个问题。OP特别要求使用catch all like。
defineProperty
不处理这种情况。问题:“即,为任何尚未定义的属性名创建getter和setter。”(他们的重点).
defineProperty
预先定义属性。OP要求的唯一方法是代理。@T.J.Crowder我明白了。你在技术上是正确的,尽管问题不是很清楚。我已经相应地调整了我的答案。此外,有些人可能真的想要我们的答案的组合(我个人有).@Andrew当我在2011年问这个问题时,我想到的用例是一个库,它可以返回一个用户可以调用
obj的对象。whateverProperty
,这样库就可以用一个通用的getter截取这个对象,并给它一个用户试图访问的属性名。因此需要“捕获所有getter和安德鲁:你的回答对我很有帮助
function MyObject() {
    var emptyValue = null;
    var obj = {};
    this.get = function(prop){
        return (typeof obj[prop] == "undefined") ? emptyValue : obj[prop];
    };
    this.set = function(prop,value){
        obj[prop] = value;
    };
}

var newObj = new MyObject();
newObj.set('myProperty','MyValue');
alert(newObj.get('myProperty'));