【问题标题】:Javascript Proxy set() local property on inherited objectsJavascript Proxy set() 继承对象的本地属性
【发布时间】:2017-01-09 07:47:18
【问题描述】:

根据MDNhandler.set()可以trap Inherited property assignment:

Object.create(proxy)[foo] = bar;

在这种情况下,如何监控和允许对继承对象进行本地分配?

var base = {
	foo: function(){
		return "foo";
	}
}

var proxy = new Proxy(base, {
	set: function(target, property, value, receiver){
		console.log("called: " + property + " = " + value, "on", receiver);
		//receiver[property] = value; //Infinite loop!?!?!?!?!
		//target[property] = value // This is incorrect -> it will set the property on base.
		
		/*
			Fill in code here.
		*/
		return true;
	}
})

var inherited = {}
Object.setPrototypeOf(inherited, Object.create(proxy));

inherited.bar = function(){
	return "bar";
}

//Test cases
console.log(base.foo); //function foo
console.log(base.bar); //undefined
console.log(inherited.hasOwnProperty("bar")) //true

【问题讨论】:

    标签: javascript inheritance proxy


    【解决方案1】:

    经过一些额外的思考,我注意到它拦截了 3 个操作:

    属性分配:proxy[foo] = bar 和 proxy.foo = bar 继承属性赋值:Object.create(proxy)[foo] = bar
    反射.set()

    但不是Object.defineProperty(),它似乎比 = 运算符还要低。

    因此以下工作:

    var base = {
        foo: function(){
            return "foo";
        }
    };
    
    var proxy = new Proxy(base, {
        set: function(target, property, value, receiver){
            var p = Object.getPrototypeOf(receiver);
          
            Object.defineProperty(receiver, property, { value: value });   // ***
            return true;
        }
    });
    
    var inherited = {};
    Object.setPrototypeOf(inherited, Object.create(proxy));
    
    inherited.bar = function(){
        return "bar";
    };
    
    // Test cases
    console.log(base.foo);                       // function foo
    console.log(base.bar);                       // undefined
    console.log(inherited.bar);                  // function bar
    console.log(inherited.hasOwnProperty("bar")) // true

    【讨论】:

    • 我怎么没想到?! :-) 你可能希望 writable: true, enumerable: true, configurable: true 在那里,使其等效。
    • 你的评论只是帮助我找到了一个错误。不知道 enumerable(和所有其他属性)默认为 false X.X
    【解决方案2】:

    我看到两个选项(也许):

    1. 将属性存储在Map 中,将各种接收器的Maps 保存在由接收器键入的WeakMap 中。通过检查Map 并在那里而不是从对象返回映射来满足get。 (还有has。)小问题是您还需要代理接收器(不仅仅是base)以处理ownKeys。所以这可能是行不通的。

    2. 设置时暂时将代理从继承链中取出。

    这是第二个:

    var base = {
        foo: function(){
            return "foo";
        }
    };
    
    var proxy = new Proxy(base, {
        set: function(target, property, value, receiver){
            const p = Object.getPrototypeOf(receiver); // ***
            Object.setPrototypeOf(receiver, null);     // ***
            receiver[property] = value;                // ***
            Object.setPrototypeOf(receiver, p);        // ***
            return true;
        }
    });
    
    var inherited = {};
    Object.setPrototypeOf(inherited, Object.create(proxy));
    
    inherited.bar = function(){
        return "bar";
    };
    
    // Test cases
    console.log("base.foo:", base.foo); // function foo
    console.log("base.bar:", base.bar); // undefined
    console.log("inherited.bar:", inherited.bar); // function bar
    console.log("inherited has own bar?", inherited.hasOwnProperty("bar")); // true

    【讨论】:

    • 抱歉,我想到了另一个使用Object.defineProperty() 的答案。如果代理捕获的内容没有那个漏洞,我认为你的答案会是最好的。
    • @blackening:毫无疑问,你的方法更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多