With ECMAScript 6 now feature complete, any further changes to the core of JavaScript would happen in ECMAScript 7. I ' m pretty excited about the changes coming in ECMAScript 6 and there is already some great ECMAScript 7 features such as and Object.observe()
asynchronous functions. While the development of ECMAScript 7 continues, I just wanted to share my personal wishlist of things this would make WRI Ting JavaScript even better and is (seemingly) within the scope of consideration for ECMAScript 7.
Some notes about the Wishlist items:
- I haven ' t found a good source of already-scheduled ECMAScript 7 features, so I don't know if any of these is already on T He roadmap or not.
- I don ' t actually care what the names of things is, I just care about the functionality.
- I ' m no expert in syntax. It's entirely possible I suggested something here's that isn ' t feasible.
Arrays
I recently came to realize that I spend a inordinate amount of time working with arrays in JavaScript, moreso than Anythi Ng else. I ' ve had a growing list of annoying things about working with arrays that has been partially solved in ECMAScript 5 and 6 . However, there still seems to be some low-handing fruit.
Array.prototype.last (), Array.prototype.first ()
The number of times I write something like each items[items.length - 1]
week drives me crazy. I just want a last()
method that does it for me. The native equivalent of this:
Array.prototype.last = function() { return this[this.length - 1];};
While I check the last item of arrays frequently, I Also check the first item frequently. So I ' d love to has as well first()
:
Array.prototype.first = function() { return this[0];};
With these-methods, a lot of my code would look cleaner:
//before if (items[0] === "(" && items[items.length - 1] === ")") { // do something}// afterif (items.first() === "(" && items.last() === ")") { // do something}
Array.prototype.isEmpty ()
Another thing I do with arrays a lot are check to see if it's empty by comparing the length to zero. I ' d much rather has a method to improve readability. Something like this:
Array.prototype.isEmpty = function() { return this.length === 0;}
Function.empty
I find myself using empty functions frequently, especially in Tests and callback-oriented functions where I don ' t actually Care-to-wait for the results. That means I usually write things like:
someAsyncMethod(function() { // noop});
The // noop
comment is there-make sure people understand I-intentionally left this function empty. I ' d much rather there is a predefined empty function that I can reuse whenever I want a throwaway function, such as:
someAsyncMethod(Function.empty);// where...Object.defineProperty(Function, "empty", { value: () => {}, writable: false, configurable: false, enumerable: true};
Object.deeppreventextensions (), Object.deepseal (), Object.deepfreeze ()
ECMAScript 5 added Object.preventExtensions()
, Object.seal()
, and Object.freeze()
. These serve to protect objects from certain types of modification, which was fantastic, except that these was shallow opera tions. For instance:
var data = { subdata: { type: "js" }};Object.freeze(data);data.subdata = {}; // fails silently in nonstrict modedata.subdata.type = "css"; // succeeds
This is working as intended, data.subdata
cannot being overwritten but data.subdata.type
can being since only freezes the properties of the Object.freeze()
ob Ject is passed. In the most cases, that's okay, but I ' ve found myself needing to apply object protection deeply, and it would is great to has Official methods that does this.
My primary use case was in reading in a JSON configuration and wanting to protect it throughout the lifetime of the Applica tion. It ' s possible to implement the fairly easily in ECMAScript 6:
Object.deepPreventExtensions = function(object) { // for avoiding circular references var handled = new WeakSet(); // recursive function function deepPreventExtensions(object) { // handle first level Object.preventExtensions(object); handled.add(object); Object.keys(object).filter(function(key) { // get keys for objects not already handled return object[key] && (typeof object[key] === ‘object‘) && !handled.has(object[key]); }).forEach(function(key) { Object.deepPreventExtensions(object[key]); }); } deepPreventExtensions(object);};
The only tricky part was handling circular references, but that's made somewhat easier by using a to track WeakSet
already-h andled objects. The same basic pattern can is applied for Object.deepSeal()
and Object.deepFreeze()
.
Defensive objects
I recently wrote a post about defensive objects. As a refresher, defensive objects is those that throw an error when you try to read a property that doesn ' t exist. This is the same as the objects work in type safe languages and is the last missing capability for accurately creating classes in JavaScript, behave as they would in and other languages.
Today, you can get pretty close:
class Person { constructor(name) { this.name = name; Object.seal(this); }}
Using the ECMAScript 6 class syntax plus Object.seal()
, you ' re able to create a object that can ' t has its properties removed or New properties added. However, accessing a nonexistent property would still just return undefined
:
var me = new Person("Nicholas");console.log(me.nme); // unfortunate typo, returns undefined
Because the property nme
doesn ' t exist, it returns if you undefined
try to access it. I recently spent a half hour tracking down a bug that is a typo of this nature and wished I had a-to-prevent it from Happening.
Adding This behavior would bring object properties inline with variables in terms of the what would happen when you try to Acce SS something that doesn ' t exist. An error was thrown when you try to read an undeclared variable; I ' d like that same behavior if you try to read a undeclared property.
I propose a method that's similar Object.preventExtensions()
to, perhaps called Object.preventUndeclaredGet()
(probably isn't the best name) that would set an internal p Roperty on a object changing the [[Get]]
behavior to throw a error when the given property doesn ' t exist. For example:
class Person { constructor(name) { this.name = name; Object.seal(this); Object.preventUndeclaredGet(this); }}var me = new Person("Nicholas");console.log(me.name); // "Nicholas"console.log(me.nme); // throws error
Adding This capability allows the create classes that correctly mimic classes in other languages. Also, if you don't seal the object, you can add new properties whenever you want; As long as you set the property value before reading it, no error would occur.
Custom Descriptor Attributes
Property descriptors seem like a great the "to" add meta information to the properties except that you cannot add unknown proper Ties. JavaScript always returns only the spec-defined attributes if you try to store a custom piece of information:
var me = {};Object.defineProperty(me, "name", { value: "Nicholas" type: "string"});var descriptor = Object.getOwnPropertyDescriptor(me, "name");console.log(descriptor.value); // "Nicholas"console.log(descriptor.type); // "undefined"
To me, the property descriptor are a great possible location for storing information related to a particular property. Besides the implications for storing type hints, you could also store relevant information about validation, data bindings , or more.
It wouldn ' t make sense-to-allow just-arbitrary attributes on the descriptor, as the language might need to add-in The future. However, adding a single property, which is designed for the custom information could work. For instance, what if the spec declared a property called to meta
contain user-defined information. meta
that would is stored and could later be retrieved exactly as-is, without the possibility of affecting the other prop Erty descriptor values or risk naming collisions with the future property descriptor attributes. For example:
var me = {};Object.defineProperty(me, "name", { value: "Nicholas" meta: { type: "string" }});var descriptor = Object.getOwnPropertyDescriptor(me, "name");console.log(descriptor.value); // "Nicholas"console.log(descriptor.meta.type); // "string"
Lightweight traits
In many ways, JavaScript have supported traits for a long time through the use of mixins. Traits is really the same thing:objects that provide a set of methods intended to being applied to another object. The Object.assign()
method was added in ECMAScript 6 to aid in this endeavor. However, it can get quite messy to use the This approach:
var trait1 = { method1: function() {}};var trait2 = { method2: function() {}};function MyObject() { // ...}Object.assign(MyObject.prototype, trait1, trait2, { method3: function() {}});
There's no-to-easily do the same thing with ECMAScript 6 classes, so you're ' d be stuck calling in the Object.assign()
constructor an D applying it to each instance.
What do I ' d like to propose are some syntactic sugar to make this easier using object literals and classes. For object literals, it would look like this:
function MyObject() { // ...}// lightweight traitsMyObject.prototype = { use trait1, use trait2, method3: function() {}};// desugars toMyObject.prototype = Object.assign({}, trait1, trait2, { method3: function() {}});
A Similar syntax can be used on ECMAScript 6 classes to specify traits for the prototype:
class MyObject { use trait1; use trait2; constructor() {} method3() {}}// desugars tofunction MyObject() { // ...}Object.assign(MyObject.prototype, trait1, trait2, { method3: function() {}});
It's entirely possible Object.assign()
that should actually being something else, perhaps something that also calls toMethod()
super
so the Binding is correct, but I think this example illustrates my point.
Conclusion
I ' m very excited to see where ECMAScript 7 was headed and hope that some of these ideas was worthwhile enough to pursue. Even if they aren ' t, ECMAScript 6 is such a superior upgrade from ECMAScript 5 that I ' m sure ECMAScript 7 'll be a really Great set of changes as well.
Disclaimer:any viewpoints and opinions expressed in the this article is those of Nicholas C. Zakas and do not, on any, R Eflect those of my employer, my colleagues, Wrox Publishing, O ' Reilly Publishing, or anyone else. I speak only to myself, not for them.
Both comments and pings are currently closed.
Related Posts
- Creating Type-safe Properties with ECMAScript 6 proxies
- Creating defensive objects with ES6 proxies
- Announcing understanding ECMAScript 6
- Private instance members with Weakmaps in JavaScript
- Understanding ECMAScript 6 Arrow Functions
My ECMAScript 7 Wishlist