对动态对象属性使用 getter / setter
Using getter / setter for dynamic object properties
我有一个名为 status
的对象,我想在其中跟踪 class.
的任何状态
除了设置各种状态外,我还想跟踪这些状态的活跃时间。现在不是为每个状态定义第二个 属性 来跟踪时间,这听起来像是 getter / setter
的工作。
这就是我被困的地方。我如何使它们动态化,以便它们触发 status
中的每个 属性?
var Person = function(options) {
this.name = options.name;
var _statusChanged = {};
var _status = {};
// How to make this dynamic?
var expr = "isOnfire";
this.status = {
get [expr]() {
console.log(_statusChanged);
return _status[expr];
},
set [expr](val) {
_status[expr] = val;
_statusChanged[expr] = new Date();
return _status[expr];
}
};
};
var John = new Person({
name: "John"
});
John.status.isOnfire = true;
John.status.hasPinkShirt = true;
console.log(John, John.status.isOnfire, John.status.hasPinkShirt);
如果您有这些列表,只需在循环中创建 getters/setters,例如:
this.status = {};
["isOnFire", "hasPinkShirt"].forEach((name) => {
Object.defineProperty(status, name {
get() {
console.log(_statusChanged);
return _status[name];
},
set(val) {
_status[name] = val;
_statusChanged[name] = new Date();
return _status[name];
}
});
});
如果它们可以是 任何东西,那么您会想要使用 Proxy
object。使用代理,您可以捕获所有 gets/sets 而无需提前知道 属性 名称:
this.status = new Proxy(_status, {
get(target, propKey, receiver) {
// handle get
return _status[propKey];
},
set(target, propKey, value, receiver) {
// handle set
_status[propKey] = value;
_statusChanged[propKey] = new Date();
return true; // Tells the proxy the assignment worked
}
});
(或者您可以使用 Reflect.get
and Reflect.set
,但 Firefox 还没有它们。)
Here's an article 更详细地介绍代理。
这是一个示例,但您需要在最新版本的 Firefox 中 运行 它,因为 support or Proxy
in the wild 地面上仍然很薄,而且根据它们的性质,您不能shim/polyfill 个代理。
(function() {
"use strict";
var _status = {};
var _statusChanged = {};
var status = new Proxy(_status, {
get(target, propKey, receiver) {
snippet.log(propKey + " requested");
return _status[propKey];
},
set(target, propKey, value, receiver) {
snippet.log(propKey + " set to " + value);
_status[propKey] = value;
_statusChanged[propKey] = new Date();
return true; // Tells the proxy the assignment worked
}
});
status.foo = "bar";
snippet.log("foo = " + status.foo);
})();
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
在您可以使用它们之前,您需要将设置状态设置为方法调用,而不是赋值。
您需要一个名为 ECMAScript 6 的对象 Proxy
。在 Firefox 中,它们默认打开。在某一时刻,它们在 Chrome 中在“experimental JavaScript" but they seem to have been removed temporarily; see this ES6 compatibility table.
下实施
此代码在 Firefox 中有效:
var output = function(text) {
var line = document.createElement('div');
line.innerHTML = text;
document.getElementById('output').appendChild(line);
}
var Person = function(options) {
this.name = options.name;
var _status = {};
var _statusChanged = {};
this.status = new Proxy(_status,{
get: function(target,property) {
return target[property];
},
set: function(target,property,value) {
_statusChanged[property] = new Date();
output("set " + property + " to " + value + " at " + _statusChanged[property]);
_status[property] = value;
}
});
this.show = function(property) {
output("Property " + property + " is " + _status[property] + " since " + _statusChanged[property]);
}
};
var John = new Person({
name: "John"
});
John.status.isOnfire = true;
John.status.hasPinkShirt = true;
John.show("isOnfire");
John.show("hasPinkShirt");
<div id="output"></div>
也许这对你有用
http://jsfiddle.net/oksbLyqf/16/
var Person = function (options) {
this.name = options.name;
var _statusChanged = {};
var _status = {};
var expr = '';
var addStatusProperty = function (prop) {
expr = prop;
Object.defineProperty(otherStatus, expr, {
get: function () {
console.log(_statusChanged);
return _status[expr];
},
set: function (val) {
_status[expr] = val;
_statusChanged[expr] = new Date();
return _status[expr];
}
});
};
var setStatusProperty = function (prop, val) {
expr = prop;
if (_status[expr]) {
otherStatus[expr] = val;
return _status[expr];
} else {
addStatusProperty(expr);
otherStatus[expr] = val;
return _status[expr];
}
};
var getStatusProperty = function (prop) {
expr = prop;
return _status[expr]
};
this.status = {
addProperty: addStatusProperty,
setProperty: setStatusProperty,
getProperty: getStatusProperty
};
var otherStatus = this.status;
};
var John = new Person({
name: "John"
});
John.status.setProperty('isOnfire', true);
John.status.setProperty('hasPinkShirt', true);
console.log(John, John.status.getProperty('isOnfire'), John.status.getProperty('hasPinkShirt'));
我有一个名为 status
的对象,我想在其中跟踪 class.
的任何状态
除了设置各种状态外,我还想跟踪这些状态的活跃时间。现在不是为每个状态定义第二个 属性 来跟踪时间,这听起来像是 getter / setter
的工作。
这就是我被困的地方。我如何使它们动态化,以便它们触发 status
中的每个 属性?
var Person = function(options) {
this.name = options.name;
var _statusChanged = {};
var _status = {};
// How to make this dynamic?
var expr = "isOnfire";
this.status = {
get [expr]() {
console.log(_statusChanged);
return _status[expr];
},
set [expr](val) {
_status[expr] = val;
_statusChanged[expr] = new Date();
return _status[expr];
}
};
};
var John = new Person({
name: "John"
});
John.status.isOnfire = true;
John.status.hasPinkShirt = true;
console.log(John, John.status.isOnfire, John.status.hasPinkShirt);
如果您有这些列表,只需在循环中创建 getters/setters,例如:
this.status = {};
["isOnFire", "hasPinkShirt"].forEach((name) => {
Object.defineProperty(status, name {
get() {
console.log(_statusChanged);
return _status[name];
},
set(val) {
_status[name] = val;
_statusChanged[name] = new Date();
return _status[name];
}
});
});
如果它们可以是 任何东西,那么您会想要使用 Proxy
object。使用代理,您可以捕获所有 gets/sets 而无需提前知道 属性 名称:
this.status = new Proxy(_status, {
get(target, propKey, receiver) {
// handle get
return _status[propKey];
},
set(target, propKey, value, receiver) {
// handle set
_status[propKey] = value;
_statusChanged[propKey] = new Date();
return true; // Tells the proxy the assignment worked
}
});
(或者您可以使用 Reflect.get
and Reflect.set
,但 Firefox 还没有它们。)
Here's an article 更详细地介绍代理。
这是一个示例,但您需要在最新版本的 Firefox 中 运行 它,因为 support or Proxy
in the wild 地面上仍然很薄,而且根据它们的性质,您不能shim/polyfill 个代理。
(function() {
"use strict";
var _status = {};
var _statusChanged = {};
var status = new Proxy(_status, {
get(target, propKey, receiver) {
snippet.log(propKey + " requested");
return _status[propKey];
},
set(target, propKey, value, receiver) {
snippet.log(propKey + " set to " + value);
_status[propKey] = value;
_statusChanged[propKey] = new Date();
return true; // Tells the proxy the assignment worked
}
});
status.foo = "bar";
snippet.log("foo = " + status.foo);
})();
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
在您可以使用它们之前,您需要将设置状态设置为方法调用,而不是赋值。
您需要一个名为 ECMAScript 6 的对象 Proxy
。在 Firefox 中,它们默认打开。在某一时刻,它们在 Chrome 中在“experimental JavaScript" but they seem to have been removed temporarily; see this ES6 compatibility table.
此代码在 Firefox 中有效:
var output = function(text) {
var line = document.createElement('div');
line.innerHTML = text;
document.getElementById('output').appendChild(line);
}
var Person = function(options) {
this.name = options.name;
var _status = {};
var _statusChanged = {};
this.status = new Proxy(_status,{
get: function(target,property) {
return target[property];
},
set: function(target,property,value) {
_statusChanged[property] = new Date();
output("set " + property + " to " + value + " at " + _statusChanged[property]);
_status[property] = value;
}
});
this.show = function(property) {
output("Property " + property + " is " + _status[property] + " since " + _statusChanged[property]);
}
};
var John = new Person({
name: "John"
});
John.status.isOnfire = true;
John.status.hasPinkShirt = true;
John.show("isOnfire");
John.show("hasPinkShirt");
<div id="output"></div>
也许这对你有用
http://jsfiddle.net/oksbLyqf/16/
var Person = function (options) {
this.name = options.name;
var _statusChanged = {};
var _status = {};
var expr = '';
var addStatusProperty = function (prop) {
expr = prop;
Object.defineProperty(otherStatus, expr, {
get: function () {
console.log(_statusChanged);
return _status[expr];
},
set: function (val) {
_status[expr] = val;
_statusChanged[expr] = new Date();
return _status[expr];
}
});
};
var setStatusProperty = function (prop, val) {
expr = prop;
if (_status[expr]) {
otherStatus[expr] = val;
return _status[expr];
} else {
addStatusProperty(expr);
otherStatus[expr] = val;
return _status[expr];
}
};
var getStatusProperty = function (prop) {
expr = prop;
return _status[expr]
};
this.status = {
addProperty: addStatusProperty,
setProperty: setStatusProperty,
getProperty: getStatusProperty
};
var otherStatus = this.status;
};
var John = new Person({
name: "John"
});
John.status.setProperty('isOnfire', true);
John.status.setProperty('hasPinkShirt', true);
console.log(John, John.status.getProperty('isOnfire'), John.status.getProperty('hasPinkShirt'));