es6代理安全深层对象

时间:2017-03-22 21:16:07

标签: javascript node.js

在访问使用Proxy不存在的属性时,我编写了一个小包装来返回undefined来代替typeError。这是代码:

function proxify(event) {
    var proxy = new Proxy(event, {
        get: function (target, property) {
            if (property in target) {
                return target[property];
            } else {
                    return '';
            }
          }
        }
    });
    return proxy;
}

当属性缺少1级深度时,此方法有效。 例如,假设obj.something不存在:

obj.something.else

将返回undefined

但是如果object属性是深层嵌套的

obj.something.else.deeper

我收到了一个typeError

我的问题是如何扩展上面的函数来处理深层嵌套对象?

THX

3 个答案:

答案 0 :(得分:4)

您需要将返回值包装在proxify函数中:

function proxify(event) {
  return isPrimitive(event) ? event : new Proxy(event, { get: getProp });
}
function isPrimitive(v) {
  return v == null || (typeof v !== 'function' && typeof v !== 'object');
}
function getProp (target, property) {
  if (property in target) {
    return proxify(target[property]);
  } else {
    return proxify({});
  }
}

说实话,你最好使用lodash's _.get()ramda's R.path()之类的东西。从第一个getProp()调用开始,无法知道评估将要进行多少深层,因此它必须始终返回原始值或“truthy”Proxy实例,以便下一个属性访问可以被拦截(如果发生)。另一方面,_.get()方法接受一个字符串,因此它可以立即从初始调用中知道您只是尝试访问这么多级别。

答案 1 :(得分:2)

正如idbehold所说,你必须返回原始值或新代理。 我认为你不需要loDash这样做,是的,你可以管理嵌套代理的深度! (见我的最后一点,deepProxy。 但是,由于我不确定你想做什么,我想把你的注意力集中在这几点上:

首次使用(模拟链):

function proxify(event){
    return isPrimitive(event) ? event : new Proxy(event,{ get: getProp });
}

function isPrimitive(v){
    return v == null || (typeof v !== 'function' && typeof v !== 'object');
}

function getProp(target, property){
    return (property in target)
        ? proxify(target[property])
        : proxify({});
}

这个代码,它将模拟嵌套属性, 但不赋予任何成员依赖(因为没有赋值,那么没有保留)。

obj.something.else = 99;
console.log(obj.something.else) // returning a new Proxy()

IMO,它没有意义,或者保留给非常具体的案例。 同样,这取决于你的目的是什么。

第二次使用(深度分配):

基本不可扩展的作业

function proxify(defprop={})
{
    return new Proxy(defprop, handler);
};
var handler = 
{
    get: function(target, property, receiver)
    {
        if(!(property in target))
            target[property] = proxify();
        return Reflect.get(target, property, receiver);
    },
};

obj.something.else = 99;
console.log(obj.something.else) // returning 99

可分配

通过使用基本的可链接代理,如果尝试设置新对象(或嵌套对象),则只会捕获此新属性的根。 没有更多可能的链接,这是不合适的,也不安全。

请记住以下情况:

  

Cyph:   但是如果object属性是深层嵌套的

     
    

obj.something.else.deeper

  

(糟糕的方式)假设这个任务:

var deeper = {toto: "titi"};
obj.something.else = deeper;

console.log(obj.something.else.toto)
// will return "titi"

obj.something.else.toto.something.else = {tutu: "tata"};
// will return a typeError Again

(好方法)传播连锁能力 您需要在setter陷阱中检查值的类型作为真实对象,并代理每个根属性。剩下的深度将由吸气剂陷阱自然转换。

var handler = 
{
    get: function(target, property, receiver)
    {
        if(!(property in target))
            target[property] = proxify();
        return Reflect.get(target, property, receiver);
    },
    set: function(target, property, value, receiver)
    {
        // extend proxify to appended nested object
        if(({}).toString.call(value) === "[object Object]")
            value = deepApply(receiver, property, value);

        return Reflect.set(target, property, value, receiver);
    },
};
var deepApply = function(receiver,property, data)
{
    var proxy = proxify();
    var props = Object.keys(data);
    var size = props.length;

    for(var i = 0; i < size; i++)
    {
        property = props[i];
        proxy[property] = data[property];
    }
    return proxy;
};

管理深度

我邀请您阅读我的实际解决方案:deepProxy

  • 可以通过proto声明自动定义级别 设置对象结构时。然后,您可以轻松了解当前楼层并为每个级别添加条件说明。
  • 可以从他的访问者那里获得财产的路径。

答案 2 :(得分:0)

我在GitHub上发布了一个库( Observable Slim ),使您可以代理对象和该对象的任何嵌套子代。它还有一些额外的功能:

  • 每当发生更改时,都会向指定的回调报告。
  • 将阻止用户尝试代理代理。
  • 保留已代理对象的存储,并将重用现有代理而不是创建新代理(非常重要的性能影响)。
  • 使用ES5编写并使用Proxy polyfill的分叉版本,因此可以相当容易地部署在较旧的浏览器中,并支持数组变异方法。

请随意看看,希望也有所贡献!