实现对任意对象的通用、轻量级和不引人注目的标记
Implement universal, lightweight, and unobtrusive tagging of arbitrary objects?
注意: 标题为的小节中的材料背景不是必不可少的。关于这个问题的全部说明已完全载于前几段
我想实现一种通用的、轻量级的、"不引人注目"的方式来"标记"任意对象。
更具体地说,我想定义(抽象)函数tag
、isTagged
和getTagged
的等价物,使得:
- 对于某些对象
o
,isTagged(t)
是true
,当且仅当t
是tag(o)
返回的值 - 对于每个对象
o
,getTagged(tag(o))
与o
相同 - 如果
t = tag(o)
,则tag(t)
应与t
相同 - 除了上述(1)、(2)和(3)中描述的行为之外,涉及
===
、tag(o)
和o
的严格身份测试应该以相同的方式进行
[EDIT:另一个要求是,实现不应以任何方式修改Object
类或任何其他标准类。]
例如:
>>> 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;
}
})();
这种方法虽然很笨拙,但至少似乎奏效了:
// requirement 1
>>> isTagged(o = "foo")
false
>>> isTagged(p = tag(o))
true
// requirement 2
>>> getTagged(p) === o
true
// requirement 3
>>> tag(p) === p
true
// requirement 4
>>> p.length
3
>>> p.toUpperCase()
"FOO"
嗯,几乎;要求(4)并不总是得到满足:
>>> o == "foo"
true
>>> p == "foo"
false
>>> o == o
true
>>> p == o
false
FWIW,这里是函数getProperties
的定义,它由tag
函数使用。欢迎批评。(警告:我是一个完全一无所知的JS noob,不知道自己在做什么!使用此功能的风险自负!)
function getProperties(o) {
var seen = {};
function _properties(obj) {
var ret = [];
if (obj === null) {
return ret;
}
try {
var ps = Object.getOwnPropertyNames(obj);
}
catch (e if e instanceof TypeError &&
e.message === "obj is not an object") {
return _properties(obj.constructor);
}
for (var i = 0; i < ps.length; ++i) {
if (typeof seen[ps[i]] === "undefined") {
ret.push(ps[i]);
seen[ps[i]] = true;
}
}
return ret.concat(_properties(Object.getPrototypeOf(obj)));
}
return _properties(o);
}
我认为你把这一切都搞得过于复杂了。没有理由需要将标记存储在对象本身上。如果创建一个使用对象指针作为键的单独对象,不仅可以节省空间,而且如果任意对象碰巧具有名为"_tagged"的属性,则可以防止任何无意的冲突。
var __tagged = {};
function tag(obj){
__tagged[obj] = true;
return obj;
}
function isTagged(obj){
return __tagged.hasOwnProperty(obj);
}
function getTagged(obj){
if(isTagged(obj)) return obj;
}
===编辑===
所以我决定花一分钟的时间来创建一个更健壮的标签系统。这就是我创造的。
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 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;
}
- 轻量级zxcvbn替代方案
- jqueryui的轻量级替代品,可在angular项目中选择
- 为任意html文档创建不引人注目的覆盖
- 不引人注目地设置属性后函数失败
- Html的轻量级树实现
- 可访问的更改菜单项,用于使用不引人注目的JS进行导航,而不是jQuery,
- html内联事件处理程序和非引人注目的事件处理程序之间括号的用法不同
- 使JavaScript不引人注目
- 无法让 Meteor 使用轻量级的 JS 触摸库,锤子.js
- 轻量级 Youtube 嵌入 + G. 分析事件跟踪
- 轻量级 Javascript 表过滤器,以最少的字符输入显示结果
- 什么是实现可拖动分隔符的轻量级脚本/jQuery 扩展
- JavaScript 可扩展树视图轻量级
- 我怎样才能使这个更轻量级的javascript
- 要使用的轻量级数据网格
- 用于存储 Javascript 应用程序的持久本地数据的轻量级解决方案
- 如何将函数不引人注目地绑定到元素's使用AJAX创建元素时单击
- 实现对任意对象的通用、轻量级和不引人注目的标记
- Dojo和javascript:onclick-on-anchor选项卡中的轻量级工具提示
- 轻量级UI框架,用于基于JS/HTML5 Webkit的移动开发,具有不错的列表性能