ECMAScript-regrets icon indicating copy to clipboard operation
ECMAScript-regrets copied to clipboard

The subtle difference between property assignment and definition

Open Ayms opened this issue 13 years ago • 0 comments

This is not exactly a regret but "how it works" or "why it is like this", trying to explain here the subtle difference between property assignment (=) and property definition (defineProperty), I hope this is not confusing (comments, corrections are welcome), apparently we need to get used to it :


var HTMLElement=function() {};

HTMLElement.prototype={
    get innerHTML() {return this.html_},
    set innerHTML(val) {this.html_=val},
    a: 'a'
};

var DIV=new HTMLElement();

DIV.innerHTML='c';
// Assignment operator "=", called as '[[Put]' below.

// If the property (own or inherited) does exist, is not an accessor and is 
// allowed to be modified, this creates a new own property 'innerHTML' 
// (if the property is inherited) or modifies the existing one.

// If the property does not exist, this creates a new own property 'innerHTML'.

// If the property is an accessor, this does trigger the accessor 
// (our case here).

console.log(DIV.innerHTML); //c
// OK, normal

Object.defineProperty(DIV,'innerHTML',{value:'b',writable : true,enumerable : true,configurable : true});
// Called as '[[DefineOwnProperty]]' below.

// This does define or modify a new 'innerHTML' own property that will 
// be returned prior to the inherited one (if it exists, our case here).

console.log(DIV.innerHTML); //b
// OK, so what ?
// Now consider for example http://wiki.ecmascript.org/doku.php?id=strawman:object_extension_literals
// To make it short the proposal is about extending an object literal :
// DIV.{width:'100px',height:'100px'}
// Surprisingly, the proposal does allow to do :
// DIV.{width='100px',height='100px'}
// the difference is that ':' stands for [[DefineOwnProperty]]
// and '=' for [[Put]]
// OK, surprising, but so what ? (again)
// Now consider that while coding, you might do :
// DIV.{innerHTML:'my html'}
// This will not have the effect you could expect, but just create a new 
// 'innerHTML' own property, therefore your div will not contain 'my html'
// Instead, you should have written :
// DIV.{innerHTML='my html'}

delete DIV.innerHTML;
// Delete the own property

console.log(DIV.innerHTML); // c
// Returns the inherited one

//Other example
console.log(DIV.a); //a
// Inherited property

DIV.a='b';

console.log(DIV.a); //b
// New own property

Object.defineProperty(DIV,'a',{value:'c',writable : true,enumerable : true,configurable : true});
// Modify the own property

console.log(DIV.a); //c

delete DIV.a;
// Delete the own property

console.log(DIV.a); //a
// Returns the inherited property

Maybe this sentence from Brendan Eich can summarize what is happening : "There really is a difference between assigning and defining in JS. Assigning runs setters, even inherited ones. Defining overrides or shadows."

Other examples can be found here : http://wiki.ecmascript.org/doku.php?id=strawman:define_properties_operator

Ayms avatar Sep 25 '12 16:09 Ayms