Robin Cafolla Tags

top

Found 1 posts matching tags: 'js'

Robin Cafolla

Get: Causing 99 Problems

Published:

Tags:

Since the start of the year I've been working on a game. In the spirit of modernity, and to avoid having to learn a new language as well as a whole new methodology, I'm writing it in JavaScript.

I've done a lot of work over the years in JS. However, I've never spent all my time, day in day out, working in it, and now that I am my eyes have opened to a few quirks the language harbours. Some of the more major annoyances are thankfully being addressed in es6 and es7, but one stood out yesterday by costing me several hours of work.

Here's some code:

var MyClass = function(){}; MyClass.prototype.properties = {}; MyClass.prototype.get = function( key ){ return this.properties[ key ]; } MyClass.prototype.set = function( key, value ){ this.properties[ key ] = value; } var instance = new MyClass(); Object.defineProperty( instance, '_getTouchedMethods', { __proto__: instance, writable: false, configurable: false, enumerable: false, value: function(){ return touchedMethods; } }); var touchedMethods = []; var proxy = new Proxy( instance, { get: function( target, property, receiver ){ if ( typeof target[property] === 'function' ) { console.log('Method ' + property + ' touched.'); touchedMethods.push( property ); } return target[ property ]; } }) proxy.set( 'foo', 'bar' );

Paste that into Firebug and you'll see it throws:

`TypeError: property descriptors must not specify a value or be writable when a getter or setter has been specified`

At first I was convinced the get method in the proxy was colliding with the Object.definePropery, and after several hours pouring through ES6 docs, stack overflow and MDN I decided this was a bug. In preparing a testcase for bugzilla I started commenting stuff out, and I realized that just the Object.defineProperty throws the error.

But why? it's a vary basic function I'm defining and there's nothing in the properties out of the ordinary. Again, I assumed I was doing something off-spec and hit the docs, but there's not a lot to Object.defineProperty, so I at least didn't waste long on it.

Eventually I concluded that there was a collision between MyClass.get and the Object.defineProperty. That in itself seemed like a bug when it hit me.

I'd originally written the define like:

Object.defineProperty( instance, '_getTouchedMethods', { __proto__: instance, writable: false, configurable: false, enumerable: false, value: function(){ return this.touchedMethods; } });

Where `this` had to take it's value from the __proto__. This then was the source of the problem, you can't use an object with a get method as the prototype for defineProperty.

Perhaps it's still a bug...