tvcutsem / harmony-reflect Goto Github PK
View Code? Open in Web Editor NEWES5 shim for ES6 Reflect and Proxy objects
Home Page: http://www.ecma-international.org/ecma-262/6.0/#sec-reflection
License: Other
ES5 shim for ES6 Reflect and Proxy objects
Home Page: http://www.ecma-international.org/ecma-262/6.0/#sec-reflection
License: Other
I get this exception when calling Proxy(...).
Error: proxies not supported on this platform
at new global.Proxy (http://localhost:55503/Core/shared-html-widgets/3rdparty/reflect.js:1992:11)
at Object.ViewModelMarshallingService._getOrCreateRemoteObject (http://localhost:55503/Core/js/angular/services/view-model-marshalling-service.js?bust=1418052137254:489:37)
Here's are my Chrome version info:
Google Chrome 39.0.2171.71 (Build officiel) m
Révision 465742dffbc8f2edcb5dacd2afc8b095199172fc-refs/branch-heads/2171_62@{#12}
Système d'exploitation Windows
Blink 537.36 (@185310)
JavaScript V8 3.29.88.17
Flash 15.0.0.239
Agent utilisateur Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36
Ligne de commande "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --harmony-proxies --flag-switches-begin --javascript-harmony --flag-switches-end
I am getting a strange error when trying to stringify a Proxy object in node.js:
$ node --harmony
> var hr = require('harmony-reflect');
undefined
> JSON.stringify(new Proxy({}, {}));
illegal access
Just the plain string illegal access
is thrown (not an Error
object). Tested with node.js v0.10.26 and v0.11.13, same behavior.
I’m trying to proxy every object in a group of objects where some might be the prototypes of others. Similar to this minimal example:
proto = {..}
proxiedProto = Proxy(proto, {
set: function(target, name, value) {
target[name] = value; return true;
}
});
obj = Object.create(proxiedProto);
proxiedObj = Proxy(obj, {
set: function(target, name, value) {
target[name] = value; return true;
}
});
The proposal for Direct Proxies in the ECMAScript wiki (http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies#interaction_with_prototypal_inheritance) suggests that setting a property of obj (for example in the set-trap of proxiedObj) will fire the set-trap of proxiedProto:
When a proxy is used as a prototype, some of its traps may get triggered not because the proxy itself was “touched” by external code, but rather an object that inherits (directly or indirectly) from the proxy
Now, I’m wondering about two things related to this quote:
First: Using the current version of this repository, whether the prototype’s set-trap fires or not seems to depend on whether the property in question was already defined in the prototype's target or not, at least in Chrome 30.0.1599.101 on my computer, as in the following two examples:
Example 1: as expected after reading the wiki:
proto = {age: 1}
proxiedProto = Proxy(proto, {
set: function(target, name, value) {
target[name] = value; return true;
}
})
obj = Object.create(proxiedProto)
obj.age = 2
console.log(obj.age === 2) // true
console.log(obj.hasOwnProperty('age')) // false
console.log(proto.age === 1) // false
Example 2: not as (I’ve) expected, only difference is that proto now is an empty object (without an ‘age’ property):
proto = {}
proxiedProto = Proxy(proto, {
set: function(target, name, value) {
target[name] = value; return true;
}
})
obj = Object.create(proxiedProto)
obj.age = 2
console.log(obj.age === 2) // true
console.log(obj.hasOwnProperty('age')) // true
console.log(proto.age === undefined) // true
Is this a bug?
Second: Given that the prototype’s trap should fire as in Example 1, is there a way to change the target in proxiedObj’s proxy-handler without triggering the set-trap of proxiedProto? Or is it basically not possible to change an inheriting object when the prototype is a proxy with a set-trap?
And there's one more question I've related to proxies as prototypes (not sure if it would be better to file another issue, let me know in that case): When proxies are used as prototypes, this can't be changed later-on. For example:
proxiedProto = Proxy({},
{set: function(target, name, value) {
target[name] = value; return true;
}
});
obj = {};
console.log(obj.__proto__ === Object.prototype); // true
obj.__proto__ = proxiedProto;
console.log(obj.__proto__ === proxiedProto); // true
obj.__proto__ = Object.prototype;
console.log(obj.__proto__ === Object.prototype); // false
console.log(obj.__proto__ === proxiedProto); // true
Maybe that's also related to #18. At least it's similarly just a matter with Chrome and not in Firefox (25.0).
Are there any plans to implement the one? )
http://whatwg.github.io/loader/
hi
any reason why this is not working?
var obj = {};
obj.name = "Func";
var t = JSON.stringify(obj); //working
var prx = new Proxy({}, {});
prx.name = "Func";
var t = JSON.stringify(prx); //not working
I'm not quite sure how to motivate this problem without describing 3 different phenomena at once so please bear with me:
{ "0": 'foo', "1": 'bar' }
instead of ['foo', 'bar']
.Object.prototype.toString.apply(candidate) === '[object Array]'
test. Proxy to Array returns [object Object]
.It's the third of these that I think is arguably a bug in the proxy implementation (or I'd like to know why not, and how to work around it!).
magi@ubuntu ~/src> node --harmony
> require('harmony-reflect')
> JSON2 = require('./json2')
> a = ['foo','bar']
[ 'foo', 'bar' ]
> p = Proxy(a, {})
{ '0': 'foo',
'1': 'bar' }
> JSON.stringify(p)
illegal access
> JSON2.stringify(p)
'{"0":"foo","1":"bar"}'
Note there that the REPL's display of p
shows it as an object with numeric keys, as I described in (2) above. So not only json2.js but also util.inspect
(which the REPL uses) is treating p
as a general Object, not as an Array.
Also note that the builtin JSON.stringify
on a proxy just fails with "illegal access".
Here's the full battery of tests I can think of for whether something is an array (all of these return true for a, but mostly not for p):
> a instanceof Array
true
> Array.isArray(a)
true
> require('util').isArray(a)
true
> Object.prototype.toString.apply(a)
'[object Array]'
> p instanceof Array
true
> Array.isArray(p)
false
> require('util').isArray(p)
false
> Object.prototype.toString.apply(p)
'[object Object]'
So the instanceof
test works on the proxy, but all the other tests fail. And a lot of code out there wants to use the Object.prototype.toString test. Now, the reasons for using the Object.prototype.toString test instead of the instanceof test might not be relevant to Node (namely, browser-side stuff with multiple frames or iframes). But is there any hope that Object.prototype.toString should be returning Array and not Object for arrays?
Some further details:
I am having an issue when using the delete operator on an object wrapped using nested proxies. An example program is:
var Reflect = require("harmony-reflect");
var handler = {
deleteProperty: function(target,name,receiver) {
return Reflect.deleteProperty(target,name,receiver);
}
};
var o = {x: 1, y: 2};
var inner = new Proxy(o, handler);
var outer = new Proxy(inner, handler);
delete outer.x;
Which in turn produces this error trace:
/Users/jackw/Developer/harmony-test/node_modules/harmony-reflect/reflect.js:1717
return handler.deleteProperty(target, name);
^
TypeError: undefined is not a function
at Object.global.Reflect.deleteProperty (/Users/jackw/Developer/harmony-test/node_modules/harmony-reflect/reflect.js:1717:22)
at Object.handler.deleteProperty (/Users/jackw/Developer/harmony-test/test.js:5:24)
at Object.Validator [as delete] (/Users/jackw/Developer/harmony-test/node_modules/harmony-reflect/reflect.js:818:20)
at Object.<anonymous> (/Users/jackw/Developer/harmony-test/test.js:13:8)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
at startup (node.js:129:16)
Assuming this is a bug and not an incorrect example on my part, I believe the issue may be related to the difference in naming between the Validator trap delete
and the Reflect function deleteProperty
.
Just wanted to point out that this library doesn't work as Proxy polyfill which might be implied from the project description or, maybe, I missed something in the readme which states how to bring Proxy into environment, that don't have those natively.
I cannot get the following example to work:
require('harmonize')(['harmony_proxies']);
require('harmony-reflect');
var os = require('os');
var p = new Proxy(os, {});
console.log(os.type())
console.log(p.type())
This is what I get as output:
Linux
(...)file.js:9
console.log(p.type())
^
TypeError: Illegal invocation
at Object.<anonymous> (/home/onaips/node-lazy-require/oi.js:9:15)
at Module._compile (module.js:435:26)
at Object.Module._extensions..js (module.js:442:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:311:12)
at Function.Module.runMain (module.js:467:10)
at startup (node.js:134:18)
at node.js:961:3
Looks like the this
context is not being properly set. Is this a bug or I shouldn't be doing it?
I'm sure this is a known issue. The v8 legacy proxy implementation seems to have a bug with get and/or set. When using a proxy as a prototype, the get and set traps should get the actual receiver of the property access as an argument. But that doesn't seem to be the case. The traps always receive just the proxy object. Here's a test.
// for node.js
if(typeof require == 'function') {
var load = require;
}
load('../reflect.js');
var RCVR = null;
function test() {
var target = {}
var proxy = Proxy(target, {
get: function(target, name, receiver) {
console.log('GET');
RCVR = receiver;
},
set: function(target, name, val, receiver) {
console.log('SET');
RCVR = receiver;
return true;
}
});
var child = Object.create(proxy);
child.foo;
console.log('get :' + (RCVR === child));
child.bar = 'bar';
console.log('set :' + (RCVR === child));
}
I spent some time trying to come up with a way to work around this bug in v8 to get inheritance working with this proxy shim. But I can't see one. this is really unfortunate because without this, nice use cases like MethodSink just don't work. Should I file this bug with v8? It's unlikely that they'll fix it considering the old proposal is likely going away.
There may also be something wrong with this test. I ran it in FF (where all the current tests pass) and it fails there. For some reason the get/set traps don't seem to be called at all in FF. I don't get the GET
output that confirms the trap. Any idea what I'm doing wrong?
As mentioned in #50, Object.defineProperties
needs to be patched similar to Object.defineProperty
, using the ES5 spec algorithm: http://ecma-international.org/ecma-262/5.1/#sec-15.2.3.7
In the direct proxies spec, built-ins on Date and RegExp should auto-unwrap the proxy:
var d = new Date()
var dp = Proxy(d,{})
Date.prototype.getTime.call(dp) // or simply: dp.getTime()
// should work, but currently fails
Similarly for e.g. RegExp.prototype.exec and RegExp.prototype.test
Similarly also for the Date and RegExp toString() method, as explained elsewhere.
All non-generic Date.prototype and RegExp.prototype methods should be patched to auto-unwrap proxies.
The spidermonkey shell uses non-standard toSource() invocations that also currently fail on proxies. Those should probably also auto-unwrap.
Tested on version 1.1.0.
> Object.freeze([1])
[ 1 ]
> void require("harmony-reflect")
undefined
> Object.freeze([1])
true
I've been exploring various concepts for trying to bring ES6 features to ES5 supporting engines (without source rewriting). One example is of bringing Name
s to ES5 (http://bbenvie.com/articles/2012-06-06/ES6-Private-Names-Shim), and collections (https://github.com/Benvie/ES6-Harmony-Collections-Shim) are trivial to implement at an API compatible level and many other features are as well. Obviously anything related to syntax changes are out. Proxies represent an interesting in between, where the syntax is fully compatible but the underlying semantics are...complicated.
In fact, it's trivial to shim most of the features of proxies as this very repo shows. The direct proxy concept is implemented on top of the original proxy api almost entirely (from a user standpoint) due to the fact that almost all of the operations in JS are already only accessible via function calls, and some of the ones that aren't still defer to JS code anyway (toString, valueOf). The only ones that are non-obvious to shim are the literal operations: get, set, delete, has, in. Using ES5 and premeditation, you can even handle get and set for existing properties.
I don't have answers to this but I thought it could potentially be in the spirit of this specific project.
The enumerate
trap fails when called on a Proxy wrapping another Proxy:
require('harmony-reflect');
function wrap(obj) {
return new Proxy(obj, {});
}
var proxy = wrap({a: 1, b: 2});
for (var prop in proxy) console.log(prop);
proxy = wrap(proxy);
for (var prop in proxy) console.log(prop);
Output:
$ node --harmony src/enumtest.js
a
b
TypeError: Object a,b has no method 'next'
at Object.Validator.enumerate (node_modules/harmony-reflect/reflect.js:1141:28)
at Object.<anonymous> (enumtest.js:11:18)
...
When explicitly implementing the trap (as return Reflect.enumerate(target)
), the error changes to:
TypeError: enumerate trap should return an iterator, got: a,b
at Object.Validator.enumerate (node_modules/harmony-reflect/reflect.js:1155:13)
at Object.<anonymous> (enumtest.js:17:18)
This is with node v0.10.29 and [email protected].
A LICENSE file would be helpful, otherwise I can't include this repo as a submodule.
Right now reflect.js in browser w/o Proxy support will fail at https://github.com/tvcutsem/harmony-reflect/blob/master/reflect.js#L1957-L1959 with Uncaught TypeError: Cannot call method 'create' of undefined
error message.
Testing master on Chrome
Version 35.0.1897.0 aura (257451)
fails testProxies. Looks like PR #27
I built node 0.7.8 on OS X Mountain Lion and am getting the error:
Error: proxies not supported on this platform
when I try to call Proxy().
Here is the code - derived from the example, that causes this to happen.
function makeProfiler(target) {
var count = Object.create(null);
return {
proxy: harmonyReflect.Proxy(target, {
get: function(target, name, rcvr) {
count[name] = (count[name] || 0) + 1;
return harmonyReflect.Reflect.get(target, name, rcvr);
}
}),
stats: count
};
}
function runApp(o) {
o.foo; o.foo; o.foo;
o.bar; o.bar;
o.baz;
}
var harmonyReflect = require( 'harmony-reflect');
var target = { foo: 42, bar: 24 };
var profiler = makeProfiler(target);
runApp(profiler.proxy);
Here is the full stack trace:
Error: proxies not supported on this platform
at Object.Proxy (/Users/dylanbarrell/Documents/src/node/node_modules/harmony-reflect/reflect.js:1702:11)
at makeProfiler (repl:4:23)
at repl:1:16
at REPLServer.eval (repl.js:110:21)
at repl.js:259:20
at REPLServer.eval (repl.js:117:5)
at Interface. (repl.js:249:12)
at Interface.emit (events.js:87:17)
at Interface._onLine (readline.js:178:10)
at Interface._line (readline.js:499:8)
I'm having trouble with another package that began requiring harmony-reflect
.
I started getting the following error (more details):
TypeError: Object prototype may only be an Object or null: true
I haven't been able to determine with what package the problem lies, but if you have any insight, it would be appreciated!
Original issue: jscs-dev/node-jscs#2026
As commented in #50, // Patches:
section in comments does not include:
defineProperty
defineProperties
getPrototypeOf
getOwnPropertyNames
setPrototypeOf
Previously this shim would not patch up Proxy if it was already defined as a function (i.e. typeof Proxy === "function"
). The rationale was that if Proxy is already defined as a function, the platform supports direct proxies and patching Proxy is not necessary.
Current firefox versions (FF 26+) do implement Proxy as a function and do support the direct proxies API, but various bugs remain so that patching Proxy is still valuable.
Commit ab5ca4c updates the library to always patch the global Proxy object if it is available, regardless of whether it is a function or not.
I hope you won't mind a user-level question here.
I am using Chrome with this library to wrap 'window' in a proxy so that I might record and replay the DOM operations. On the operation 'window.document', I fail. I need to return the proxy of window.document so subsequent operations on the return will also enter the proxy code. However, window.document is own frozen data of window and the test in reflect.js line 1063 throws a TypeError. As far as I can see from the code, I could not succeed in wrapping returns from window.document, and yet my case seems quite similar to the ones discussed as use cases for Proxy. Any hints?
I'm not sure where this would best exist, if anywhere at all, but it seems like it's already been useful just pulling together notes on a few bugs and issues with the various implementations and continuing iteration of those. While they should always be reported as bugs to the tracker for the implementation first, it still seems useful to note them and workarounds for the short term, and also as a kind of historical documentation of the various issues that inevitably come up along the way in implementing new APIs, especially one this grandiose. Individual bug tracs have a tendency to get deeply buried amongst the mountain of issues filed in engine repo history logs without much context to draw from after the fact.
I haven't figured out why yet, but requiring 'harmony-reflect' in react-native is giving me "SyntaxError: Unexpected end of script".
I am using harmony and the Proxy object is present.
I'm trying to basically write a dsl, translating dot and bracket notation into operations on a remote database. With a bit of help i came up with;
function QueryBuilder() {
if (this instanceof QueryBuilder == false) return new QueryBuilder();
var self = this;
var fn = function () {
//ignored
};
fn.self = self;
this.proxy = new Proxy(fn, QueryBuilderProxyHandler);
this.parts = [];
return this;
}
var QueryBuilderProxyHandler = {
get: function(target, name){
target.self.parts.push(name);
return target.self.proxy;
},
apply: function(target, thisValue, args) {
target.self.parts.push({that:thisValue, args: args});
return target.self.proxy;
}
}
var thing = new QueryBuilder();
thing.proxy.test.this.out(1);
console.log(thing);
This logs the operations, but is shared and requires multiple calls.
Next I updated an old example from https://github.com/DavidBruant/HarmonyProxyLab to use the new api;
(function() {
var DeclarativeObject, declo;
DeclarativeObject = function() {
var constructorTrap, firstHandler, getTrap, middleHandler, propNames;
propNames = void 0;
getTrap = function(rec, name) {
propNames.push(name);
return Proxy(constructorTrap, middleHandler);
};
middleHandler = {
get: getTrap
};
constructorTrap = function() {
return propNames.slice();
};
firstHandler = {
get: function(rec, name) {
propNames = [];
return getTrap.apply(this, arguments);
}
};
return Proxy({}, firstHandler);
};
declo = new DeclarativeObject();
console.log(declo.a.b.c.ef(48));
console.log(declo.xo['cc'].xo.ke());
}).call(this);
This works, but as soon as i try adding the apply method all i get are TypeErrors. What is the proper way to do this?
Something is wrong with Array.concat when it operates on a proxy. This may be a special case of issue #6 but I'm opening a new issue so we can more easily track the details.
var a = ['x', 'y'];
var h = {};
var aProxy = Proxy(a, h);
var aConcat = [].concat(a);
var aProxyConcat = [].concat(aProxy);
d8> print(aConcat.length);
2
d8> print(aProxyConcat.length);
1
I've confirmed that this bug exists with the latest version of harmony-reflect (0.0.7) and with today's trunk version of V8.
I fail to use the Proxy get handler with a ES6 Symbol as property name:
var Reflect = require('harmony-reflect');
var p = new Proxy(Object.create(null), {
get: function(target, property) {
return 'bar';
}
});
console.log( p['foo'] );
console.log( p[Symbol('fooSym')] );
Installing harmony-reflect (version 1.4.2) in a node repl crashes it on TAB completion:
$ node --harmony_proxies
> require("harmony-reflect")
{ getOwnPropertyDescriptor: [Function],
defineProperty: [Function],
deleteProperty: [Function],
getPrototypeOf: [Function],
setPrototypeOf: [Function],
preventExtensions: [Function],
isExtensible: [Function],
has: [Function],
get: [Function],
set: [Function],
enumerate: [Function],
ownKeys: [Function],
apply: [Function],
construct: [Function] }
> ** pressing TAB key ** readline.js:925
throw err;
^
TypeError: Object prototype may only be an Object or null: true
at setPrototypeOf (native)
at Function.Object.setPrototypeOf (.../node_modules/harmony-reflect/reflect.js:1655:14)
at Object.prim_defineProperty.set (.../node_modules/harmony-reflect/reflect.js:1634:21)
at completionGroupsLoaded (repl.js:875:21)
at REPLServer.complete (repl.js:767:11)
at REPLServer.complete [as completer] (repl.js:315:10)
at REPLServer.Interface._tabComplete (readline.js:375:8)
at REPLServer.Interface._ttyWrite (readline.js:872:16)
at ReadStream.onkeypress (readline.js:106:10)
at emitTwo (events.js:100:13)
$ node -v
v5.5.0
Es6 Classes: Class constructors cannot be invoked without 'new' try following
"use strict"
var Reflect = require('harmony-reflect');
class UsersController{
constructor(name){
this.name = name
}
hello(){
return this.name
}
}
var obj = Reflect.construct(UsersController, ["somename"])
console.log(obj.hello())
Hello :]
require('harmony-reflect');
var myProxy = new Proxy({
valueOf : function () {
return 0;
}
} ,{
get : function (target, name) {
return myProxy;
}
});
console.log(myProxy * 1); // should say 0
And the error I get :
TypeError: Cannot convert object to primitive value
at repl:1:21
at REPLServer.self.eval (repl.js:110:21)
at repl.js:249:20
at REPLServer.self.eval (repl.js:122:7)
at Interface.<anonymous> (repl.js:239:12)
at Interface.EventEmitter.emit (events.js:95:17)
at Interface._onLine (readline.js:202:10)
at Interface._line (readline.js:531:8)
at Interface._ttyWrite (readline.js:760:14)
at ReadStream.onkeypress (readline.js:99:10)
Looks like something is wrapped here by the library when it shouldn't but I'm not sure of this.
Any idea ?
I'm writting a module that creates objects whose keys have a timeout and when it expires the keys are automatically deleted.
The code is very easy to follow:
"use strict";
require ("harmony-reflect");
var harmony = module.exports = {};
harmony.create = function (args){
args = args || {};
if (!("ttl" in args)) return {};
if (typeof args.ttl !== "number" || args.ttl < 0){
throw new Error ("Invalid ttl value.");
}
var timers = {};
return Proxy ({}, {
set: function (target, key, value, receiver){
if (!(key in target) && args.ttl){
timers[key] = setTimeout (function (){
delete target[key];
delete timers[key];
if (args.expire) args.expire (key);
}, args.ttl);
}
return Reflect.set (target, key, value, receiver);
},
deleteProperty: function (target, key){
var id = timers[key];
if (id){
clearTimeout (id);
delete timers[key];
}
return Reflect.deleteProperty (target, key);
}
});
};
When a new key is added to the proxy a timeout is set and when the user manually deletes the key the timeout is cleared.
But I have a question. If I enumerate the keys with a for-in loop, what happens if the key is deleted because the timer expires WHILE the loop is being executed?
For example:
var ttl = require (...);
var o = ttl.create ({ ttl: 1000, expire: function (key){ ... } }); // o is the proxy
o.a = 1;
o.b = 2;
o.c = 3;
for (var p in o){
...
// o.c expires and is deleted BEFORE p gets the value of "c".
}
What will happen in this case? The for-in loop checks the existence of the key before it is copied to the p
variable?
Thanks
I suspect this is because the get trap is overriding the apply trap because the method is accessed before it is invoked. But wanted to check it's not due to my own bad code. Thanks!...
require('harmony-reflect');
function getApplyProxy(fn) {
console.log(fn); //logged as expected
//get trap also required?...
return Proxy(
fn,
{ apply: function() {
console.log(arguments)
}}
)
}
var fnMonitor = Proxy(
{},
{ get: function(t,p) {
return (typeof t[p] == 'function' ? getApplyProxy(t[p]) : t[p]);
}}
);
var Obj = function() {};
Obj.prototype = fnMonitor;
var a = new Obj;
a.fn = function() {};
a.fn(); //undefined(!)
Getting Uncaught ReferenceError: Proxy is not defined
error with Chrome stable v36 or safari.
Works fine with Chrome beta v37 or latest stable Firefox.
how to reproduce:
access the following URL in Chrome v36 (stable) and see the console.
http://xmlking.github.io/spa-starter-kit/
This is only possible to do in SpiderMonkey but it still may be worth doing.
var proxy = new Proxy({}, {});
proxy.method();
Will cause the following
1.) proxy.[[Get]]('method')
, returns undefined
2.) proxy.[[Get]]('__noSuchMethod__')
If you implement the get
trap to check for 'noSuchMethod' that can be reflected as the invoke trap.
I believe this behavior was introduced in harmony-reflect v0.0.5 while fixing #13.
The auto-unwrapping assumes Object.prototype.toString will only be called on objects. But lots of code calls it on other types to figure out what type they're dealing with.
Here's what one would normally expect for this behavior:
magi@ubuntu ~/s/d/foo> node --harmony
> ({}).toString.apply(1)
'[object Number]'
> ({}).toString.apply(true)
'[object Boolean]'
> ({}).toString.apply('asdf')
'[object String]'
> ({}).toString.apply(null)
'[object Null]'
> ({}).toString.apply(undefined)
'[object Undefined]'
> ({}).toString.apply([])
'[object Array]'
> ({}).toString.apply({})
'[object Object]'
Here's what you get with harmony-proxies v0.0.5:
magi@ubuntu ~/s/d/foo> node --harmony
> require('harmony-reflect')
{ snip }
> ({}).toString.apply(1)
TypeError: Invalid value used as weak map key
at WeakMap.get (native)
at Number.builtin (/home/magi/node_modules/harmony-reflect/reflect.js:1500:34)
at repl:1:16
> ({}).toString.apply(true)
TypeError: Invalid value used as weak map key
at WeakMap.get (native)
at Boolean.builtin (/home/magi/node_modules/harmony-reflect/reflect.js:1500:34)
at repl:1:16
> ({}).toString.apply('asdf')
TypeError: Invalid value used as weak map key
at WeakMap.get (native)
at String.builtin (/home/magi/node_modules/harmony-reflect/reflect.js:1500:34)
at repl:1:16
> ({}).toString.apply(null)
TypeError: Invalid value used as weak map key
at WeakMap.get (native)
at builtin (/home/magi/node_modules/harmony-reflect/reflect.js:1500:34)
at repl:1:16
> ({}).toString.apply(undefined)
TypeError: Invalid value used as weak map key
at WeakMap.get (native)
at builtin (/home/magi/node_modules/harmony-reflect/reflect.js:1500:34)
at repl:1:16
> ({}).toString.apply([])
'[object Array]'
> ({}).toString.apply({})
'[object Object]'
Would it be possible to add at least traps for Object.*
static methods on platforms that do not support real proxies?
I'm currently playing with some code where at least such basic support would be useful, and from my understanding it shouldn't be hard to implement it since overrides for those methods are already implemented and just need some basic Proxy
implementation for storing and accessing handlers.
I'm trying to figure out what I am doing wrong. In the following code I create aProxy
which only logs the get() call. Then I call Object.create(aProxy)
. I'm trying to puzzle out the resulting object's behavior and deal with it.
(function() {
var obj = {};
var handler = {
get: function(target, name, receiver) {
console.log('get ' + name);
return target[name];
}
};
var aProxy = Proxy(obj, handler);
var created = Object.create(aProxy);
console.log('created.__proto__', created.__proto__);
console.log('created.__proto__ === aProxy ', created.__proto__ === aProxy);
console.log('Object.getPrototypeOf(created) === aProxy ', Object.getPrototypeOf(created) === aProxy);
})();
When the code runs, the handler is called twice and we log an object, false and true:
get __proto__ testObjectCreated.html:9
created.__proto__ Object {} testObjectCreated.html:15
get __proto__ testObjectCreated.html:9
created.__proto__ === aProxy false testObjectCreated.html:17
Object.getPrototypeOf(created) === aProxy true testObjectCreated.html:18
This code acts as if created.__proto__
first calls [[Get]] on created
, finds nothing in own properties, then calls [[Get]] on the first proto chain link, finds a proxy, triggers the .get
trap, logs, then returns Object
as the proto value of {}
and logs it.
The subsequent lines show that created.__proto__
is not equivalent to Object.getPrototypeOf(created)
; the former is actually created.__proto__._proto__
while the latter is the correct created.__proto__
.
Since created
is not a proxy, to workaround this we need to discover in the get
handler that we are a proxy for proto and return ourselves. Then we have to avoid getting the wrong result if we call aProxy.__proto__
.
Have you encountered this and do you have any suggestions?
In io.js, if multiple dependencies use require('harmony-reflect)
then we get TypeError: primCreate is not a function
.
Adding a global to ensure it has not already run seems to fix it.
I'm tested with reflect.js Edge browser, but native Proxy stop working.
I am in a situation where i want to proxy a base class ( not it's instance ) and let other classes extend that base class and call magical static methods.
var handler = {
get: function(target,name){
if(target[name]){
return target[name]
}else{
// call some magic method
return 'foo'
}
},
}
class Model{
}
var proxyModel = new Proxy(Model,handler)
class User extends proxyModel{
}
But it fails saying 17270 segmentation fault iojs --harmony_proxies test/poly.js
I noticed that when using your attributes.js example I get a strange <error: illegal access> error in the stack trace of any method that I call when the class is wrapped in AttributeProxy. It doesn't "seem" to affect anything, but was wondering if this is normal? Thanks.
In node.js:
require('harmony-reflect');
function AttributeProxy(target) {
return Proxy(target, {
get: function(target, name, receiver) {
if (name in target) { return target[name]; }
// everything not found on the target object itself should
// be looked up in the target's _attributes map
return target._attributes[name];
},
set: function(target, name, val, receiver) {
if (name in target) {
target[name] = val;
return true;
}
// everything not found on the target object itself should
// be added to the target's _attributes map
target._attributes[name] = val;
return true;
}
});
}
var Person = function() {
this._attributes = {};
return AttributeProxy(this);
};
Person.prototype.walk = function() {
console.log('Person is walking');
console.log(new Error().stack);
};
var Female = function() {
// call "super" constructor
return Person.call(this);
}
// make Female inherit from Person
Female.prototype = Object.create(Person.prototype);
Female.prototype.shop = function() {
console.log('Female is shopping');
console.log(new Error().stack);
}
console.log(new Error().stack);
// tests
var person = new Person();
person.hair = 'black';
person.walk(); // methods are called normally
var female = new Female();
female.hair = 'blonde';
female.walk(); // methods are called normally
female.shop(); // methods are called normally
Output:
Error: Regular Stack Trace
at Object.<anonymous> (/var/guestweb/new.jump.omnitarget.com/attributes_test.js:45:13)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:492:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
Person is walking
Error: Person.walk
at <error: illegal access>
at Object.<anonymous> (/var/guestweb/new.jump.omnitarget.com/attributes_test.js:50:8)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:492:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
Person is walking
Error: Person.walk
at <error: illegal access>
at Object.<anonymous> (/var/guestweb/new.jump.omnitarget.com/attributes_test.js:54:8)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:492:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
Female is shopping
Error: Female.shop
at <error: illegal access>
at Object.<anonymous> (/var/guestweb/new.jump.omnitarget.com/attributes_test.js:55:8)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:492:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
I'd like to use this module as a direct proxy shim, especially for educational purposes. However, I don't want people learning about and using the deprecated traps and reflect APIs.
I could manually monkey-patch the code, but it would be nice if there was a way to turn it off.
I use this library internally for my project https://github.com/scotthovestadt/node-schema-object
harmony-reflect has a bad interaction with very popular library lodash - many lodash methods (such as _.keys, _.merge, and others) will trigger this warning.
Can we setup harmony-reflect with a way to turn the warning off, even if the default behavior is to have it on?
The first line of [[setPrototypeOf]] fails if the argument is undefined:
https://people.mozilla.org/~jorendorff/es6-draft.html#sec-ordinary-object-internal-methods-and-internal-slots-setprototypeof-v
But reflect.js does not:
function testSetPrototypeOf() {
var obj = {};
var shouldThrow;
try {
Object.setPrototypeOf(obj, undefined);
} catch (ex) {
shouldThrow = ex;
}
assert(shouldThrow);
}
I believe the issue here is that reflect.js implements Object.setPrototypeOf(obj, newProto)
using obj.__proto__
setter, but somehow these operations are not consistent on Chrome at least.
Hello,
Currently lots of libs and browsers with Proxy object still call the getOwnPropertyNames method. It would be good for the shim to show a warning and call ownKeys instead of throwing an error, as currently it stops execution.
What do you think?
Thank you!
Environment: Node.js
Example:
const f = function () {
};
const pf = Proxy(f, ...);
pf.prototype = {}; // This statement will cast exception
var Reflect = require('harmony-reflect')
var Foo = class{}
Reflect.construct(Foo, [])
This throws the following error:
TypeError: Class constructors cannot be invoked without 'new'
at new <anonymous> (path/to/harmony-reflect/test/testReflect.js:313:19)
at Object.global.Reflect.construct (path/to/harmony-reflect/reflect.js:1976:43)
at path/to/harmony-reflect/test/testReflect.js:325:29
at test (path/to/harmony-reflect/test/testReflect.js:328:4)
at Object.<anonymous> (path/to/code/harmony-reflect/test/testReflect.js:333:3)
at Module._compile (module.js:413:34)
at Object.Module._extensions..js (module.js:422:10)
at Module.load (module.js:357:32)
at Function.Module._load (module.js:314:12)
at Function.Module.runMain (module.js:447:10)
There seems to be an issue with how proto is patched to use Object.setPrototypeOf.
Currently, setting the proto property of an object causes a TypeError:
TypeError: Generic use of proto accessor not allowed
The error occurs, for example, when using test/testProxies.html to run testProxies.js in the testSetPrototypeOf.
Is there another way to patch proto?
I used Chrome 29.0.1547.22 beta (with Experimental JavaScript for the old Harmony proxies and Harmony Weak Maps).
My current solution is to prevent the patch (not executing the function after _var _proto__setter), change Object.setPrototypeOf to directly set the proto property, and then consistently use
Object.setPrototypeOf(target, newProto)
instead of
target.proto = newProto
in the project... :-/
Give ES6 class, how to trap prototype method calls?
class Account {
constructor(name, amount) {
this.name = name;
this.amount = amount;
}
withdraw(arg) {
this.amount = this.amount - arg;
}
deposit(arg) {
this.amount = this.amount + arg;
}
}
var proxyAccount = new Proxy(new Account('sumo', 500) , {} );
proxyAccount.deposit(100); //want to trap this method call
proxyAccount.withdraw(50);
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.