Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>OK, now I've read the attached code (but could not follow all of it). Lacks some comments, but I won't bitch about that, my own codes are not better as I don't expect anybody to read or understand them :-)</p> <p>You are right, the part where you extend the native prototypes is scary. From what I understand, you define an accessor property on the Number or String prototype before returning a number / string. Both on getting and setting, the accessor property is overwritten by a data property (???), then the whole property is deleted, before you store / return the value. This seems to be a clever hack to allow custom properties on primitive values, yet:</p> <ul> <li>There is a high risk of collisions. It might be possible to lower that by using the <code>this</code> value as a key in a lookup table (to differentiate <code>(5).x</code> from <code>(3).x</code>), but it still can't be fully avoided.</li> <li>Properties that remove themselves on accessing / setting are extremely unintuitive. Avoid that.</li> <li>arbitrarily changing accessor properties on the prototype of primitives are costly. That's 4 performance-contras combined. No engine will be able to optimize this. And you seem to use them quite often.</li> </ul> <p>If you really needed this (I still didn't get your reason), I'd use a variant with a lookup-table. It should reduce collisions (not sure how your code handled them), does not change the accessor properties ones they're defined and is therefore more persistent (though it might leak then):</p> <pre><code>// Let's call this // PRIMITIVE PROXIES // as they proxy real objects behind primitive values var proxy = _.map( { // some map that works on Objects string: String.prototype, number: Number.prototype }, function closure(type, proto) { var table = {}; function setupProperty(prop) { if (prop in proto) return; // ah, we already proxied this kind of object Object.defineProperty(proto, prop, { configurable:true, // for deleting get: function getter() { // "this" is the primitive value if (!this in table) return undefined; return table[this][prop]; // get prop from obj }, set: function setter(val) { if (this in table) table[this][prop] = val; // pass val to obj } }); } return { create: function createProxy(prim, obj) { if (prim in table) // we already did create a proxy on this primitive return; // let's abort. You might continue to overwrite table[prim] = obj; Object.getOwnPropertyNames(obj).forEach(setupProperty); return prim; // the new "proxy" }, move: function moveName(from, to) { if (to in table) return false; table[to] = table[from]; delete table[from]; return true; } }; }); proxy.create = function(prim, obj) { return proxy[typeof prim].create(prim, obj); }; proxy.move = function(from, to) { return proxy[typeof from].create(from, to); }; // USAGE: // proxy.create works just like Object.extend &gt; var c = {ann: 58}, &gt; o = {blah: 98}; &gt; proxy.create(c.ann, o); &gt; 58..blah 98 &gt; c.ann.blah 98 &gt; (58).blah = 60; &gt; o {blah: 60} &gt; var num = c.ann; // 58 &gt; c.ann.blah = function(){return "Hello"}; &gt; num.blah() "Hello" &gt; proxy.move(c.ann, c.ann = 78); &gt; c.ann 78 &gt; (58).blah undefined &gt; c.ann.blah() "Hello" &gt; // getters/setters for properties are global: &gt; c.ann.blub = "something"; // does not work, there is no getter &gt; c.ann.blub undefined &gt; proxy.create(58, {blub: "foo"}) &gt; c.ann.blub // still returns undefined &gt; c.ann.blub = "bar"; // but can be set now &gt; (58).blub + (78).blub "foobar" &gt; // infinite lookup loops are possible: &gt; proxy.create("loop", {x:"loop"}); &gt; "loop" === "loop".x true &gt; "loop".x.x.x.….x "loop" </code></pre> <p>However, there is one thing you will never be able to work around:</p> <blockquote> <p>Unlike objects, primitive values are not unique; they have no identity.</p> </blockquote> <p>You will never be able to distinguish <code>c.ann</code> from <code>58</code>, or <code>"loop"</code> from <code>"loop".x</code>, and so both will have a property or not. This is not a good premise to build an API upon.</p> <p>So, I still recommend to use <code>Number</code> and <code>String</code> objects. You don't need to subclass them (as shown in my previous answer), as you don't seem to have (m)any methods on them, so you can easily build them:</p> <pre><code>c.ann = new Number(58); c.ann.blah = 98; return c; </code></pre> <p>There should be hardly a difference, expect for the <code>typeof</code> operator. Could you maybe add some more examples that use the <code>__default</code> value?</p> <blockquote> <p>but how can I make it different without having to use valueOf if the chain end object is a primitive?</p> </blockquote> <p>To answer this simple question: That guy was right, it cannot be done in JavaScript without hacking native prototypes. And you are right, the hack is quite ugly :-)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload