Wednesday, April 20, 2016

Proxies on regexps and boxed primitives

Leave a Comment

Let's say I have a regexp which I want to handle via a proxy (in order to trap property accesses etc.):

proxy = new Proxy(/x/, {}); 

But when I try to use the proxy as a regexp:

proxy.test('x') 

I get

Uncaught TypeError: Method RegExp.prototype.test called on incompatible receiver [object Object]

A similar error occurs with 'x'.match(proxy).

Or consider proxying a boxed primitive:

proxy = new Proxy(Object(5), {}); 

But when I try to use the proxy as part of an expression, expecting a value of 6:

proxy + 1 

I get

Uncaught TypeError: Number.prototype.valueOf is not generic(…)

So my questions are:

  1. Can I proxy a regexp in such a way that the proxy functions as the regexp does in constructions such as regexp.test?

  2. Can I proxy a boxed primitive in such a way that the valueOf behavior continues to work?

1 Answers

Answers 1

Built-in types / objects can have so called "internal slots" which carry state that is not accessible from outside. Some methods depend on this state and therefore can't operate if it's missing.

These internal slots are not accessible through standard means when an object is proxied. Looking at the specification you will often encounter "if X does not have a [[y]] internal slot throw a TypeError exception". That's why proxying built-in types often does not work as expected. For the same reason you cannot do something like Number.prototype.valueOf.call({}).

A workaround is to bind the function directly to the target of the proxy:

var proxy = new Proxy(/x/, {   get: function(target, key) {     if (typeof target[key] === 'function') {       return target[key].bind(target);       }      return target[key];  } }); 

This example creates a new function on every call. A more sophisticated solution would cache the functions and and create a new function only for problematic methods.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment