Quantcast
Channel: ClearScript
Viewing all articles
Browse latest Browse all 2297

New Post: Object.defineProperty on host object

$
0
0
Greetings!

The behavior you're seeing is by design.

Host object properties are accessed via interception, which takes precedence over normal JavaScript property access. Failure to retrieve a nonexistent host property triggers the default handling to provide access to the prototype chain; that's why getters work as expected. Property assignment on the other hand throws an exception if it fails on the host side; this is done to capture as much error information as possible at the point of failure.

This asymmetric behavior is analogous to JavaScript's default property access protocol, where reads use the prototype chain but writes do not. On the other hand, as you've noticed, it also makes most host objects non-extensible on the JavaScript side. An exception is when a host object is itself extensible, such as an instance of System.Dynamic.ExpandoObject.

That's the real issue here; host objects and script objects can have conflicting notions of extensibility. It might be possible to detect that a host object is non-extensible and fall back to JavaScript semantics, but that determination would nontrivial, and it isn't clear that the resulting behavior would be appropriate in every case. In any case, ClearScript currently doesn't do that.

One possibility might be to wrap the host object in a JavaScript proxy, but currently there's a bug that prevents proxies from targeting host objects directly. Still, you might be able to use the following JavaScript function, or something similar, to produce an object with the desired behavior:
function createProxy(obj) {
    returnnew Proxy(function () {}, {
        apply: function (target, thisArg, argumentsList) {
            return Reflect.apply(obj, thisArg, argumentsList);
        },
        construct: function(target, argumentsList, newTarget) {
            return Reflect.construct(obj, argumentsList);
        },
        get: function (target, key, receiver) {
            let value = Reflect.get(obj, key);
            return (value === undefined) ? Reflect.get(target, key, receiver) : value;
        },
        set: function (target, key, value, receiver) {
            if (Reflect.has(obj, key))
                return Reflect.set(obj, key, value);
            return Reflect.set(target, key, value, receiver);
        }
    });
}
An alternative might be to create your own JavaScript proxy object that forwards selected methods and properties to the host object.

Good luck!

Viewing all articles
Browse latest Browse all 2297

Trending Articles