Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/392.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 实现对任意对象的通用、轻量级和不引人注目的标记?_Javascript_Delegation - Fatal编程技术网

Javascript 实现对任意对象的通用、轻量级和不引人注目的标记?

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的行为应相

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
    的行为应相同
  • [编辑:另一项要求是,实现不应以任何方式修改
    对象
    类或任何其他标准类。]

    例如:

    >>> 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函数,使其变得相当简单。