Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a future proof way to add properties to native browser objects given "use strict" behavior?

I noticed recently that when "use strict"; mode is on in browsers many properties on native objects become unsettable.

For example

function() {   "use strict";   var div = document.createElement("div");   div.offsetLeft = 0;   }(); 

Ignore the fact that setting offsetLeft is stupid. That's not the point.

If you run this in Chrome or Firefox you'll get an error

Uncaught TypeError: Cannot set property offsetLeft of #<HTMLElement> which has only a getter(…) 

Remove the "use strict"; and the error goes away.

So here's the problem. Let's change offsetLeft to something I might use in my own code

function createElementAndAssociateData(data) {   "use strict";   var div = document.createElement("div");   div.userdata = data;   }; 

This works great, except 2 years from a new HTML5 spec comes out and decides that all HTMLElements have userdata attribute that's read only. Suddenly my code breaks everywhere I used "use strict";.

Is this a time bomb waiting to happen as more and more properties are added to native HTML5 objects?

Is there a safe way to use "use strict"; and add custom properties to native HTML5 objects or should adding any kind of property to a native browser object never be done?

Note: I don't believe obfusticating the property names is an acceptable solution. Sure I could change userdata to mycompanyname_myappname_userdata but that's kind of beside the point. Is there some other solution or is adding custom properties to native HTML5 objects in strict mode an anti-pattern?

like image 286
gman Avatar asked Sep 13 '15 22:09

gman


2 Answers

Yes: ES6 symbols

The problem with properties is that their name is a string. Then, two different codes may choose to use the same name for different purposes, and the result may be disastrous.

To solve this problem, ECMAScript 6 introduces a new type: Symbol.

You can use it like this:

var s1 = Symbol("My property"); object[s1] = "Some data 1"; object[s1]; // "Some data 1" 

Then, even if some other code decides to use a symbol with the same description, there won't be any collision:

var s2 = Symbol("My property"); // Same description :S object[s2] = "Some data 2"; object[s2]; // "Some data 2" object[s1]; // "Some data 1" -- No problem :) 
like image 83
Oriol Avatar answered Oct 08 '22 20:10

Oriol


The intended way of adding custom properties is with HTMLElement.dataset.

var div = document.createElement("div"); div.dataset.yourCustomProperty = 'some data'; div; // <div data-your-custom-property="some data"> div.dataset.yourCustomProperty; // "some data" 

This reflects the custom data-* attributes.

Note that .dataset.camelCase reflects data-camel-case and the other way round.

like image 31
Sebastian Simon Avatar answered Oct 08 '22 19:10

Sebastian Simon