在普通JS对象上使用`get`和`apply`代理陷阱

时间:2017-01-29 04:31:17

标签: javascript ecmascript-6

以下代码是一个简单的代理,它会记录被困的“获取”:

var p = new Proxy({}, {
    get: function(target, property, receiver) {
        console.log("getting: ", property);
        return target[property];
    }
});

当我将此强制转换为"hello " + p的字符串时,我在控制台中获得以下输出:

getting:  Symbol(Symbol.toPrimitive)
getting:  valueOf
getting:  toString
getting:  Symbol(Symbol.toStringTag)
"hello [object Object]"

到目前为止一切都很好,但让我们做一些偷偷摸摸的事情并代理一个函数,但实际上仍然使用它作为我们在上一个例子中使用的普通对象的代理。我想要这个的原因是因为我希望能够在get上捕获applyobj

请注意return target.obj部分 - 我们实际上仍然使用它来代理obj - 这只是我们通过 fn 做的 / p>

var fn = function(){};
fn.obj = {};
var p = new Proxy(fn, {
    get: function(target, property, receiver) {
        console.log("getting: ", property);
        return target.obj[property];
    }
});

现在,我认为这会产生与"hello " + p的最后一个示例完全相同的输出,但我错了:

getting:  Symbol(Symbol.toPrimitive)
getting:  valueOf
getting:  toString
getting:  Symbol(Symbol.toStringTag)
"hello [object Function]"

请注意,它已生成Function字符串标记而非Object字符。这里发生了什么?就好像在toString而不是fn上调用obj一样。 (编辑:但我们可以添加fn.toString = function(){ return "fn"; }并且它不会更改输出,因此可能不是fn在此处进行字符串化处理?)

如果你在那里弹出一个debugger语句,你会看到它实际上正如你所期望的那样返回fn.obj.toString,但由于某种原因,最终输出是一个函数而不是一个对象(尽管我不完全确定哪个功能)。谢谢你的帮助!

P.S。我没有解释我的用例的完整上下文(简短版本:它适用于DSL,因此弯曲“良好做法”很好),因此建议替代模式来实现get和{ {1}}对象上的陷阱(实际上)可能与我的特定情况无关。我真的很想理解为什么上述方法不像我期望的那样工作,但也希望确保问题足够广泛,以帮助处于类似情况的未来读者。

1 个答案:

答案 0 :(得分:1)

我想我发现了这个错误。当我们返回一个函数时,看起来我们需要bind它到target.obj,否则它被绑定到某个函数。我并没有完全抓住this的东西,但我认为这是有道理的。所以这是更新的,有效的代码:

var fn = function(){};
fn.obj = {};
fn.toString = function(){ return "fn"; }
var p = new Proxy(fn, {
    get: function(target, property, receiver) {
        console.log("getting: ", property);
        let result = target.obj[property];
        if(typeof result === 'function') {
          result = result.bind(target.obj);
        }
        return result;
    }
});