On Sat, Sep 17, 2011 at 10:14 AM, Xavier MONTILLET <span dir="ltr"><<a href="mailto:xavierm02.net@gmail.com" target="_blank">xavierm02.net@gmail.com</a>></span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<br>
When I say Firefox says, you can't I mean you really can't:<br>
<br>
( function ( ) {<br>
    'use strict';<br>
    function Constructor ( ) { }<br>
    Object.defineProperty( Constructor.prototype, 'property', {<br>
        value: 'prototype',<br>
        writable: false<br>
    } );<br>
    var object = new Constructor( );<br>
    object.property = 'instance';// Error: 'object.property is read-only' (in Firefox)<br>
} )( );<br>
<br>
I'm quite sure this is a bug.</blockquote><div><br></div><div>Yes, as Brendan says, ES5.1 demands that it throw a TypeError.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

 But I find this behavior interesting.<br>
Defining properties of the prototype with Object.defineProperty lets<br>
you prevent other instances or anything else from modifying common<br>
methods.<br></blockquote><div><br></div><div>Hi Xavier, despite appearances, this is not a protection mechanism and in fact provides no protection. The following returns 'instance' on Firefox, as it must according to the ES5.1 spec:</div>

<div><br></div><div><div>( function ( ) {<br>   'use strict';<br>   function Constructor ( ) { }<br>   Object.defineProperty( Constructor.prototype, 'property', {<br>       value: 'prototype',<br>

       writable: false<br>   } );<br>   var object = new Constructor( );<br>   Object.defineProperty(object, 'property', {value: 'instance'});</div><div>   return object.property;</div><div>
} )( );<br></div></div><div><br></div><div>The behavior is there for compatibility with ES3, not for protection. In fact, from a protection perspective, this behavior is quite unfortunate. It means that if you lock down your primordial prototypes naively, as SES currently does during its initialization, to prevent prototype poisoning and the implicit sharing of prototypes from being a communications channel, then legacy programs that do not monkey patching of primordial prototypes, as so should be SES-compatible, nevertheless fail to override inherited methods by simple assignment. This incompatibility is only an irritation, since it provides no protection.</div>

<div><br></div><div>Fortunately, there is a less naive way to lock down the primordial prototypes that don't create this incompatibility. SES will move to that soon.</div><div>
<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
But most of the time, at least for methods, you want them to remain<br>
the same for the life of the object.<br>
Here is an example:<br>
Let's say you want to prevent anything stupid from happening to the<br>
methods you need:<br>
<br>
function Constructor( ) { }<br>
Object.defineProperty( Constructor.prototype, 'method', {<br>
    value: function ( ) { },<br>
    writable: false<br>
} );<br>
<br>
Now, your instances are "safe" since their method can't be removed.<br>
But sometimes, you don't even want the person using the object to be<br>
able to set another next method for you object.<br>
You could prevent him from doing so by doing this:<br>
<br>
function Constructor ( ) {<br>
    Object.defineProperty( this, 'method', {<br>
        value: function ( ) { },<br>
        writable: false<br>
    } );<br>
}<br>
<br>
but then, your methods won't be shared between instances.<br></blockquote><div><br></div><div>This is the right thing surprisingly often, although it does cause an extra allocation per method per instance on most modern JS engines. Although each instance gets its own method object, all these method objects still do share code. So it depends on why you want sharing between instances.</div>

<div><br></div><div>If what you want is to place a protected method on the prototype and prevent anyone outside the abstraction from overriding this method on the instance, you can do this without the extra allocation by having the constructor seal, freeze, or preventExtensions on the instance, depending on what kind of protection you want. Note that you still can't prevent overriding by "external" inheritance, i.e., inheritance outside the abstraction:</div>

<div><br></div><div>  var naughty = Object.create(new Constructor(), {</div><div>    method: { value: function myNaughtyOverrideMethod() {...}}</div><div>  });</div><div><br></div><div>If you then invoke naughty.foo(), where foo is inherited from Constructor.prototype that does a "this.method()", the .method() that foo() will invoke is your naughty override.</div>

<div><br></div><div>The overall lesson is that it is tricky, but not impossible, to write defensive code using "this" in a secured JavaScript. If you avoid "this" in your code, as a simple variant of your method-per-instance pattern can, then it becomes vastly easier to write defensive code in a secured JS.</div>

<div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
----------------------------------------------------------<br>
<br>
To put it in a nuttshell:<br>
- Is it the normal behavior that if a property is protected on the<br>
prototype, you can't set it on the object?<br></blockquote><div><br></div><div>Using assignment, you can't. Using Object.defineProperty, you can, so long as the object is still extensible. Thus it is a legacy compatibility irritant, rather than something offering any protection.</div>

<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
- I think it is a behavior that could be used in some cases, even<br>
though it isn't suited as default behavior.<br></blockquote><div><br></div><div>I would enjoy seeing an example where this half-protection is actually useful.</div></div><div><br></div>-- <br>    Cheers,<br>    --MarkM<br>