为非显式局部变量定义Setter / Getter:不可能? [英] Defining Setter/Getter for an unparented local variable: impossible?

查看:217
本文介绍了为非显式局部变量定义Setter / Getter:不可能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

之前有一些关于StackOverflow的问题,如何通过范围链访问局部变量,例如,如果你想使用括号符号和字符串引用局部变量,你需要像 __ local __ [varName] 。到目前为止,我还没有找到甚至最简单的方法来完成这一点,并没有提出一个方法后几个小时利用我知道的每个技巧。

There's a few previous questions on StackOverflow questioning how one goes about accessing local variables via the scope chain, like if you wanted to reference a local variables using bracket notation and a string, you'd need something like __local__["varName"]. Thus far I haven't found even the hackiest method for accomplishing this, and haven't come up with a method after hours of exploiting every trick I know.

目的因为它是在任意非显式变量上实现getters / setters。 Object.defineProperties或 __ defineGet / Setter __ 需要调用上下文。对于全局或窗口上下文中的属性,您可以实现具有用于直接引用对象的setter / getter的目标。

The purpose for it is to implement getters/setters on arbitrary unparented variables. Object.defineProperties or __defineGet/Setter__ require a context to be called on. For properties in the global or window contexts you can accomplish the goal of having a setter/getter for direct references to the object.

Object.defineProperty(this, "glob", {get: function(){return "direct access"})
console.log(glob); //"direct access"

即使在我使用自定义扩展的测试中,在任何窗口创建之前运行,其中上下文是实际的全局上下文,甚至试图在全局上下文中直接调用这个崩溃我的程序,我可以毫不费力地将其关闭:

Even in my tests with a custom extension I compiled into a modified Chromium that runs prior to any window creation where the context is the actual global context, and even trying to call this directly in the global context crashes my program, I can pull this off without a hitch:

Object.defineProperty(Object.prototype, "define", {
    value: function(name, descriptor){
        Object.defineProperty(this, name, descriptor);
    }
};
define("REALLYglobal", {get: function(){ return "above window context"; }});

旧的 __ defineGet / Setter __ 也可以在该上下文中工作,而不指定要调用的对象(在Firefox中不起作用)

And it is then available in all frames created later as a global routed through the specified getter/setter. The old __defineGet/Setter__ also works in that context without specifying what to call it on (doesn't work in Firefox though, the method above does).

因此,基本上可以为对象上的任何变量定义get / set守卫,包括窗口/全局上下文,直接调用对象(你不需要 window.propname ,只是 propname )。这是无法引用非父类型作用域变量的问题,是唯一可以在可访问范围中但不具有可寻址容器的类型。当然,它们也是最常用的,所以它不是一个边缘的情况。这个问题也超越了ES6 / Harmony中Proxies的当前实现,因为它是一个问题,特别是无法使用语言的语法来解决本地对象的容器。

So basically it's possible to define get/set guards for any variable on an object, including the window/global context with direct call to the object (you don't need window.propname, just propname). This is the issue with being unable to reference unparented scoped variables, being the only type that can be in an accessible scope but have no addressable container. Of course they're also the most commonly used too so it's not an edge case. This problem also transcends the current implementation of Proxies in ES6/Harmony since it's a problem specifically with being unable to address a local object's container with the language's syntax.

想要能够做到这一点是,它是唯一的障碍,允许重载大多数数学运算符用于复杂的对象,如数组和哈希和导出复杂的结果值。我需要能够挂钩到setter在一个值被设置的对象类型我设置为重载的情况下。没有问题,如果对象可以是全局的或可以包含在父对象,这可能是我会去的。它仍然可用于 a.myObject ,但目标是使其尽可能透明地使用。

The reason I want to be able to do this is that it's the only barrier to allow overloading of most math operators for use in complex objects like arrays and hashes and deriving a complex resulting value. I need to be able to hook into the setter in cases where a value is being set on an object type I've set up for overloading. No problem if the object can be global or can be a contained in a parent object, which is probably what I'll just go with. It's still useful with a.myObject, but the goal is to make it as transparently usable as possible.

不但是只有这样才能真正有用:

Not only that, but it'd just be really useful to be able to accomplish something like this:

var point3d = function(){
    var x, y, z;
    return {
        get: function(){ return [x, y, z]; },
        set: function(vals){ x=vals[0]; y=vals[1]; z=vals[2]; }
    };
};

(这类似于ES6的解构,但有更多的一般应用程序实现附加到获取/不仅仅是传输复杂的值)。即使这个基本的代码将完全失败:

(That is similar to ES6's destructuring but has more general applications for implementing functionality attached to getting/setting and not just transporting complex values). Even this basic code will completely fail:

var x = {myname: "intercept valueOf and :set: to overload math ops!", index: 5};
x++; //x is now NaN if you don't implement a setter somehow

黑客的解决方案是,在这一点上,它只是一个强烈的好奇心,我是否可以实现,即使它要求打破每一个最佳实践存在。我通过做重定义/拦截/修改 Object.prototype.valueOf / toString 等操作,使Firefox和Chrome崩溃了几百次$ c> Function.prototype Function.prototype.constructor Function.prototype.call/apply arguments.callee.caller 等,有无限递归错误,并且试图追溯审核钻机上下文。我唯一能做的工作是基本上包装了eval和动态构建代码块,这是一个桥梁太远,我真的不能使用。唯一其他远程成功的路径是使用与结合预定义所有局部变量在一个容器,但是这显然是非常干扰的问题使用

I don't care how hacky the solution is, at this point it's just an intense curiosity for me as to whether it can be accomplished, even if it requires breaking every best practice that exists. I've crashed Firefox and Chrome a few hundred times in pursuit of this so far by doing things like redefining/intercepting/modifying Object.prototype.valueOf/toString, Function.prototype Function.prototype.constructor, Function.prototype.call/apply, arguments.callee.caller, etc. with infinite recursion errors and whatnot in attempts to jury rig contexts retroactively. The only thing that I've been able to make work is wrapping basically the whole thing with eval and dynamically building code chunks, which is a bridge too far for me to ever actually use. The only other remotely successful route was in using with combined with pre-defining all local variables on a container, but that's obviously very intrusive on top of the issues with using with.

推荐答案

这是目前在使用代理的环境中可能的。这将节点> 0.6运行为 node --harmony_proxies 或> 0.7与 node --harmony 。铬金丝雀(不知道如果它已经离开)在约:标志在底部,实验javascript。 Firefox已经有一段时间没有标志。

This is currently possible in environments with Proxies. That would be node > 0.6 run as node --harmony_proxies or >0.7 with node --harmony. Chromium Canary (not sure if it's out of that yet) in about:flags at the bottom, experimental javascript. Firefox has had it for a while with no flags.

所以这可能不会工作,当ES6更官方,但它的工作到一定程度现在。 >

So this probably won't work when ES6 becomes more official, but it works to an extent now.

  var target = (function(){
    var handler = Proxy.create(Proxy.create({
      get: function(r, trap){
        return function(name,val,c,d){
          if (trap === 'get' || trap === 'set') {
            name = val;
            val = c;
          }
          console.log('"'+trap + '" invoked on property "'+name+'" ' + (val?' with value "'+val+'"':''));
          switch (trap) {
            case 'get': return target[name];
            case 'set': return target[name] = val;
            case 'has': return name in target;
            case 'delete': return delete target;
            case 'keys': return Object.keys(target);
            case 'hasOwn': return Object.hasOwnProperty.call(target, name);
            case 'getPropertyDescriptor':
            case 'getOwnPropertyDescriptor': return Object.getOwnPropertyDescriptor(target, name);
            case 'getPropertyNames':
            case 'getOwnPropertyNames': return Object.getOwnPropertyNames(target);
            case 'defineProperty': return Object.defineProperty(target, name, val);
          }
        }
      }
    }))

    var target = {
      x: 'stuff',
      f: { works: 'sure did' },
      z: ['overwritten?']
    };


    with (handler){
      var z = 'yes/no';
      if (x) {
        //x
      } else {
        x = true;
      }
      console.log(f.works);
      if (f.works) {
        f.works = true;
        delete f;
      }

    }
    return target
  })()
   // "getPropertyDescriptor" invoked on property "z" 
   // "getPropertyDescriptor" invoked on property "z" 
   // "getPropertyDescriptor" invoked on property "x" 
   // "get" invoked on property "x" 
   // "getPropertyDescriptor" invoked on property "console" 
   // "getPropertyDescriptor" invoked on property "f" 
   // "get" invoked on property "f" 
   // sure did
   // "getPropertyDescriptor" invoked on property "f" 
   // "get" invoked on property "f" 
   // "getPropertyDescriptor" invoked on property "f" 
   // "get" invoked on property "f" 
   // "getPropertyDescriptor" invoked on property "f" 

   target: { x: 'Stuff', f: { works: true },  z: ['overwritten?'] }

碰到或错过,你需要注意不要只是看一个代理在调试器中。我不得不把这个东西封装在一个闭包中,以防止代理在全局范围内结束,或者它每次崩溃的帧。要点是,它在某种程度上工作,没有什么别的。

Hit or miss and you need to take care not to blow up your browser by simply looking at a Proxy in the debugger. I had to wrap that thing in a closure to keep the proxy from ending up in the global scope or it crashed the frame every single time. Point is that it works to some extent, where nothing else does.

这篇关于为非显式局部变量定义Setter / Getter:不可能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆