Hacker News new | ask | show | jobs
by mannix 4707 days ago
I have a question, since this has been bugging me with other js MV* frameworks lately... Is the set() method necessary for updating single attribute? All browsers have supported getter/setter APIs (__defineGetter__ and Object.defineProperty), why not take advantage of them? Being able to say this would be cool:

    div.color = 'blue';
instead of:

    div.set({ color: 'blue' }); or div.set('color', 'blue');
Or would this cause other problems that I'm not thinking of?

Edit: my ruby cap is on a little tight today. Javascript programmers might not expect extra logic to be run just by updating a property. I still think it would be cool though :)

5 comments

Many of these frameworks want to support IE 8, which is the default browser of windows 7. IE 8 only supports Object.defineProperty with DOM objects[0], which can be infuriating.

No one should use __defineGetter__ and __defineSetter__ because they are non-standard and deprecated[1].

[0] http://kangax.github.io/es5-compat-table/#define-property-ie...

[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

Edit: left this tab open and I see this point has since been made, but I will leave the comment anyways.

Yes, the only reason I'd use __defineGetter__ would be a fallback for Object#defineProperty.

I'm curious if the IE8 limitation could be worked around, using something like:

    if (ie8)
        RactiveBaseModel.prototype = HTMLAnchorElement.prototype;
It's definitely something I've thought about. There are a few reasons I still prefer ractive.set( keypath, value ), which I'll try and articulate:

1. It's explicit, and therefore more predictable. I get itchy when libraries take control out of my hands. Though I understand not everyone feels that way!

2. Performance. Getters and setters have a penalty (or did the last time I looked into it in any depth).

3. It only works for existing properties. With Ractive you don't have to declare the 'shape' of your entire model up-front - you can start with a completely empty model and set properties as and when it's convenient. (With ES6 and Object.observe maybe we can sidestep that issue one day.)

4. Performance (again). If you set several properties simultaneously (e.g. ractive.set({ opacity: 0.5, left: 10 }), or whatever), then updates won't happen until all the new data has been taken account of.

5. That irritating thing that happens when you try to do foo.bar.baz = 'bob' and you get an error because foo.bar is undefined.

6. There are some cases where you want to do something like ractive.set( keypath + '.complete', true ) - you can only do that with string-based keypaths.

As for emn13's suggestion of Knockout-style observables, my own experience is that having to inherit from custom observable classes gets cumbersome quite quickly. But different strokes for different folks!

If getters/setters aren't available, I still vastly prefer plain functions (e.g. knockout) to the stringized setter.

I mean, why would

   model.set('someProp', 'someVal');
   x = model.get('someProp');
be better than

   model.someProp('someVal');
   x = model.someProp();
And the second one is likely to perform better, allows better tooling support (nice to have), is shorter, and allows representing a property as a concept in itself `model.someProp`. You can still access a property with a variable name in the (unusual) case you need to.

If you really insist on explicit set/get, then you can still have...

   model.someProp.set('someVal');
   x = model.someProp.get();
Which still has no downside I can think of, and since this is JS, if you have a variable prop name, you can fall back to...

Pretty please, will the unnecessary strings die?

IE8 doesn't support it for non-DOM objects.
Crap. you're right. that's probably a dealbreaker.
ES5 specifically has Object.defineProperty. Which works on all current browsers and Node. Rich what do you think?