Javascript 实现对任意对象的通用、轻量级和不引人注目的标记?
NB:标题为背景的小节中的材料不重要。上述各段充分说明了这一问题 我想实现一种通用、轻量级和“不引人注目”的方式来“标记”任意对象 更具体地说,我想定义(抽象)函数Javascript 实现对任意对象的通用、轻量级和不引人注目的标记?,javascript,delegation,Javascript,Delegation,NB:标题为背景的小节中的材料不重要。上述各段充分说明了这一问题 我想实现一种通用、轻量级和“不引人注目”的方式来“标记”任意对象 更具体地说,我想定义(抽象)函数tag、istaged和gettaged的等价物,以便: istaged(t)为true当且仅当t是tag(o)为某些对象o返回的值时 gettaged(tag(o))对于每个对象都与o相同 如果t=tag(o),则tag(t)应与t相同 除了上述(1)、(2)和(3)中描述的行为,以及涉及=的严格身份测试外,标记(o)和o的行为应相
tag
、istaged
和gettaged
的等价物,以便:
istaged(t)
为true
当且仅当t
是tag(o)
为某些对象o
返回的值时李>
gettaged(tag(o))
对于每个对象都与o
相同李>
t=tag(o)
,则tag(t)
应与t
相同李>
=
的严格身份测试外,标记(o)
和o
的行为应相同对象
类或任何其他标准类。]
例如:
>>> isTagged(o = "foo")
false
>>> isTagged(t = tag(o))
true
>>> getTagged(t) === o
true
>>> tag(t) === t
true
>>> t.length
3
>>> t.toUpperCase()
"FOO"
下面是我解决这个问题的最佳途径。它(几乎)是通用的,但是,很快就会清楚,它是任何东西,而不是轻量级!!!(另外,它还没有完全满足上面的要求4,所以它不像我希望的那样“不引人注目”。此外,我对它的“语义正确性”有严重的怀疑。)
此解决方案包括使用“代理对象”p
包装要标记的对象o
,并将o
(无论是“拥有”还是“继承”)的所有属性复制到p
我的问题是:
是否可以在不复制标记对象的所有属性的情况下实现上述规范
背景 下面是上面提到的实现。它依赖于实用函数
getProperties
,其定义(FWIW)在最后给出
function Proxy (o) { this.__obj = o }
function isTagged(t) {
return t instanceof Proxy;
}
function getTagged(t) {
return t.__obj;
}
var tag = (function () {
function _proxy_property(o, pr) {
return (typeof pr === "function")
? function () { return pr.apply(o, arguments) }
: pr;
}
return function (o) {
if (isTagged(o)) return o;
if (typeof o.__obj !== "undefined") {
throw TypeError('object cannot be proxied ' +
'(already has an "__obj" property)');
}
var proxy = new Proxy(o);
var props = getProperties(o); // definition of getProperties given below
for (var i = 0; i < props.length; ++i) {
proxy[props[i]] = _proxy_property(o, o[props[i]]);
}
return proxy;
}
})();
……嗯,差不多了;并非总是满足要求(4):
>>> o == "foo"
true
>>> p == "foo"
false
>>> o == o
true
>>> p == o
false
FWIW,这里是函数
getProperties
的定义,该函数由标记使用。欢迎批评。(警告:我是一个完全无知的JS noob,不知道自己在做什么!使用此功能的风险自负!)
函数getProperties(o){
var-seen={};
函数属性(obj){
var-ret=[];
if(obj==null){
返回ret;
}
试一试{
var ps=Object.getOwnPropertyNames(obj);
}
catch(e如果e instanceof TypeError&&
e、 消息==“对象不是对象”){
返回属性(对象构造函数);
}
对于(变量i=0;i
你把事情复杂化了:
var tag = function(o) {
Object.defineProperty(o, '__tagged', {
enumerable: false,
configurable: false,
writable: false,
value: "static"
});
return o;
}
var isTagged = function(o) {
return Object.getOwnPropertyNames(o).indexOf('__tagged') > -1;
}
你把事情复杂化了:
var tag = function(o) {
Object.defineProperty(o, '__tagged', {
enumerable: false,
configurable: false,
writable: false,
value: "static"
});
return o;
}
var isTagged = function(o) {
return Object.getOwnPropertyNames(o).indexOf('__tagged') > -1;
}
我认为你把这一切都复杂化了。没有理由需要将标记存储在对象本身上。如果创建一个单独的对象,将该对象的指针用作键,不仅可以节省空间,而且可以防止在任意对象碰巧具有名为“_taged”的属性时发生任何意外碰撞 ==编辑== 所以我决定花一分钟的时间来创建一个更健壮的标签系统。这就是我创造的
var tag = {
_tagged: {},
add: function(obj, tag){
var tags = this._tagged[obj] || (this._tagged[obj] = []);
if(tag) tags.push(tag);
return obj;
},
remove: function(obj, tag){
if(this.isTagged(obj)){
if(tag === undefined) delete this._tagged[obj];
else{
var idx = this._tagged[obj].indexOf(tag);
if(idx != -1) this._tagged[obj].splice(idx, 1);
}
}
},
isTagged: function(obj){
return this._tagged.hasOwnProperty(obj);
},
get: function(tag){
var objects = this._tagged
, list = []
;//var
for(var o in objects){
if(objects.hasOwnProperty(o)){
if(objects[o].indexOf(tag) != -1) list.push(o);
}
}
return list;
}
}
不仅可以标记对象,还可以指定不同类型的标记,并以列表的形式检索具有特定标记的对象。让我给你举个例子
var a = 'foo'
, b = 'bar'
, c = 'baz'
;//var
tag.add(a);
tag.add(b, 'tag1');
tag.add(c, 'tag1');
tag.add(c, 'tag2');
tag.isTagged(a); // true
tag.isTagged(b); // true
tag.isTagged(c); // true
tag.remove(a);
tag.isTagged(a); // false
tag.get('tag1'); // [b, c]
tag.get('tag2'); // [c]
tag.get('blah'); // []
tag.remove(c, 'tag1');
tag.get('tag1'); // [b]
我认为你把这一切都复杂化了。没有理由需要将标记存储在对象本身上。如果创建一个单独的对象,将该对象的指针用作键,不仅可以节省空间,而且可以防止在任意对象碰巧具有名为“_taged”的属性时发生任何意外碰撞 ==编辑== 所以我决定花一分钟的时间来创建一个更健壮的标签系统。这就是我创造的
var tag = {
_tagged: {},
add: function(obj, tag){
var tags = this._tagged[obj] || (this._tagged[obj] = []);
if(tag) tags.push(tag);
return obj;
},
remove: function(obj, tag){
if(this.isTagged(obj)){
if(tag === undefined) delete this._tagged[obj];
else{
var idx = this._tagged[obj].indexOf(tag);
if(idx != -1) this._tagged[obj].splice(idx, 1);
}
}
},
isTagged: function(obj){
return this._tagged.hasOwnProperty(obj);
},
get: function(tag){
var objects = this._tagged
, list = []
;//var
for(var o in objects){
if(objects.hasOwnProperty(o)){
if(objects[o].indexOf(tag) != -1) list.push(o);
}
}
return list;
}
}
不仅可以标记对象,还可以指定不同类型的标记,并以列表的形式检索具有特定标记的对象。让我给你举个例子
var a = 'foo'
, b = 'bar'
, c = 'baz'
;//var
tag.add(a);
tag.add(b, 'tag1');
tag.add(c, 'tag1');
tag.add(c, 'tag2');
tag.isTagged(a); // true
tag.isTagged(b); // true
tag.isTagged(c); // true
tag.remove(a);
tag.isTagged(a); // false
tag.get('tag1'); // [b, c]
tag.get('tag2'); // [c]
tag.get('blah'); // []
tag.remove(c, 'tag1');
tag.get('tag1'); // [b]
很抱歉:我忘了提到实现不应该以任何方式修改标准
对象
类(或任何其他标准类)。我已经编辑了我的帖子,明确了这个额外的要求。抱歉我的疏忽。它不会修改标准类,它只会修改您正在标记的对象,并且当您使用(var k in o)的时它不会显示代码>好的,我明白了。感谢您的澄清。很抱歉:我忘了提到实现不应该以任何方式修改标准对象
类(或任何其他标准类)。我已经编辑了我的帖子,明确了这个额外的要求。抱歉我的疏忽。它不会修改标准类,它只会修改您正在标记的对象,并且当您使用(var k in o)的时它不会显示代码>好的,我明白了。感谢您的澄清。仍然有一个理由将标记存储在对象本身上:垃圾收集器。这是一个很好的观点。如果删除了该对象,还需要将其从集合中删除。不过,我们可以编写一个delete函数,使其变得非常简单。在对象本身上存储标记还有一个原因:垃圾收集器。这是一个很好的观点。如果删除了该对象,还需要将其从集合中删除。不过,可以编写一个delete函数,使其变得相当简单。