惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Forbes - Security
Forbes - Security
大猫的无限游戏
大猫的无限游戏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Jina AI
Jina AI
美团技术团队
博客园 - 聂微东
博客园 - 叶小钗
Security Latest
Security Latest
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园_首页
Spread Privacy
Spread Privacy
J
Java Code Geeks
雷峰网
雷峰网
宝玉的分享
宝玉的分享
C
Cyber Attacks, Cyber Crime and Cyber Security
P
Privacy International News Feed
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Threat Research - Cisco Blogs
The Hacker News
The Hacker News
量子位
L
LINUX DO - 热门话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
G
GRAHAM CLULEY
D
Darknet – Hacking Tools, Hacker News & Cyber Security
月光博客
月光博客
腾讯CDC
Last Week in AI
Last Week in AI
人人都是产品经理
人人都是产品经理
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Tor Project blog
罗磊的独立博客
V
Vulnerabilities – Threatpost
Apple Machine Learning Research
Apple Machine Learning Research
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
有赞技术团队
有赞技术团队
Project Zero
Project Zero
Hugging Face - Blog
Hugging Face - Blog
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Tenable Blog
MyScale Blog
MyScale Blog
T
The Exploit Database - CXSecurity.com
GbyAI
GbyAI
博客园 - 【当耐特】
O
OpenAI News
Schneier on Security
Schneier on Security
S
Secure Thoughts
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Securelist
博客园 - 司徒正美

Dmitri Pavlutin Blog

Pure Functions in JavaScript: A Beginner's Guide Record Type in TypeScript: A Quick Intro How to Write Comments in React: The Good, the Bad and the Ugly 4 Ways to Create an Enum in JavaScript React forwardRef(): How to Pass Refs to Child Components TypeScript Function Types: A Beginner's Guide How to Use v-model to Access Input Values in Vue Mastering Vue refs: From Zero to Hero Environment Variables in JavaScript: process.env 5 Must-Know Differences Between ref() and reactive() in Vue How to Destructure Props in Vue (Composition API) Triangulation in Test-Driven Development How to Use nextTick() in Vue Programming to Interface Vs to Implementation A Smarter JavaScript Mapper: array.flatMap() Array Grouping in JavaScript: Object.groupBy() How to Access ES Module Metadata using import.meta JSON Modules in JavaScript How to Trim Strings in JavaScript TypeScript Function Overloading How to Debounce and Throttle Callbacks in Vue How to Show/Hide Elements in Vue Sparse vs Dense Arrays in JavaScript How to Fill an Array with Initial Values in JavaScript Covariance and Contravariance in TypeScript What are Higher-Order Functions in JavaScript? How to Use TypeScript with React Components Index Signatures in TypeScript How to Use React useReducer() Hook unknown vs any in TypeScript A Guide to React Context and useContext() Hook How to Use Promise.any() 2 Ways to Remove a Property from an Object in JavaScript 'return await promise' vs 'return promise' in JavaScript How to Use Promise.allSettled() How to Use fetch() with JSON JavaScript Promises: then(f,f) vs then(f).catch(f) What is a Promise in JavaScript? How to Use Promise.all() A Simple Guide to Component Props in React Don't Stop Me Now: How to Use React useTransition() hook A Simple Explanation of JavaScript Variables: const, let, var ES Modules Dynamic Import How to Memoize with React.useMemo() How to Cleanup Async Effects in React Why Math.max() Without Arguments Returns -Infinity How to Debounce and Throttle Callbacks in React Don't Confuse Function Expressions and Function Declarations in JavaScript How to Use ES Modules in Node.js Solving a Mystery Behavior of parseInt() in JavaScript How to Use Array Reduce Method in JavaScript 3 Ways to Merge Arrays in JavaScript A Guide to Jotai: the Minimalist React State Management Library The Difference Between Values and References in JavaScript How to Implement a Queue in JavaScript A Helpful Algorithm to Determine "this" value in JavaScript React useRef() Hook Explained in 3 Steps 7 Interview Questions on "this" keyword in JavaScript. Can You Answer Them? How to Greatly Enhance fetch() with the Decorator Pattern 7 Interview Questions on JavaScript Closures. Can You Answer Them? What's a Method in JavaScript? array.sort() Does Not Simply Sort Numbers in JavaScript How to Solve the Infinite Loop of React.useEffect() The New Array Method You'll Enjoy: array.at(index) What's the Difference between DOM Node and Element? Why Promises Are Faster Than setTimeout()? Everything About Callback Functions in JavaScript How React Updates State 5 Mistakes to Avoid When Using React Hooks 5 Best Practices to Write Quality JavaScript Variables Type checking in JavaScript: typeof and instanceof operators 3 Ways to Check if a Variable is Defined in JavaScript React Forms Tutorial: Access Input Values, Validate, Submit Forms Prototypal Inheritance in JavaScript How to Timeout a fetch() Request How to Learn JavaScript If You're a Beginner A Simple Explanation of React.useEffect() A Simple Explanation of JavaScript Iterators How to Use React Controlled Inputs Everything about null in JavaScript How to Use Fetch with async/await Getting Started with Arrow Functions in JavaScript An Interesting Explanation of async/await in JavaScript Front-end Architecture: Stable and Volatile Dependencies Is it Safe to Compare JavaScript Strings? How to Access Object's Keys, Values, and Entries in JavaScript What Actually is a String in JavaScript? 3 Ways to Shallow Clone Objects in JavaScript (w/ bonuses) Checking if an Array Contains a Value in JavaScript JavaScript Event Delegation: A Beginner's Guide How to Parse URL in JavaScript: hostname, pathname, query, hash 3 Ways to Detect an Array in JavaScript How to Get the Screen, Window, and Web Page Sizes in JavaScript 3 Ways to Check If an Object Has a Property/Key in JavaScript How to Compare Objects in JavaScript Object.is() vs Strict Equality Operator in JavaScript Own and Inherited Properties in JavaScript 5 Differences Between Arrow and Regular Functions How to Use Object Destructuring in JavaScript Your Guide to React.useCallback()
Why Object Literals in JavaScript Are Cool
Dmitri Pavlutin · 2016-07-20 · via Dmitri Pavlutin Blog

Before ECMAScript 2015 object literals (also named object initializers) in JavaScript were quite elementary. It was possible to define 2 types of properties:

  • Pairs of property names and related values { name1: value1 }
  • Getters { get name(){..} } and setters { set name(val){..} } for computed property values

Sadly, the object literal possibilities match into a single example:


var myObject = {

myString: 'value 1',

get myNumber() {

return this._myNumber;

},

set myNumber(value) {

this._myNumber = Number(value);

},

};

myObject.myString; // => 'value 1'

myObject.myNumber = '15';

myObject.myNumber; // => 15


JavaScript is a prototype based language, so everything is an object. It is a must that language to provide easy constructs when it comes to objects creation, configuration and accessing prototypes.

It's a common task to define an object and setup it's prototype. I always felt that setting up the prototype should be allowed directly in the object literal, using a single statement.

Unfortunately the limitations of the literal didn't allow to achieve that with a straightforward solution. You had to use Object.create() in combination with the object literal to setup the prototype:


var myProto = {

propertyExists: function(name) {

return name in this;

},

};

var myNumbers = Object.create(myProto);

myNumbers['array'] = [1, 6, 7];

myNumbers.propertyExists('array'); // => true

myNumbers.propertyExists('collection'); // => false


In my opinion, it's an uncomfortable solution. JavaScript is prototype based, why so much pain to create objects from a prototype?

Fortunately the language is changing. Many things that were relatively frustrating in JavaScript are solved step by step.

This article demonstrates how ES2015 solves the problems described above and improves the object literal with additional goodies:

  • Setup the prototype on object construction
  • Shorthand method declarations
  • Make super calls
  • Computed property names

Also let's look in the future and meet the new proposals (at stage 2): rest and spread properties of an object.

Infographic

1. Setup the prototype on object construction

As you know already, one option to access the prototype of an existing object is applying the getter property __proto__:


var myObject = {

name: 'Hello World!',

};

myObject.__proto__; // => {}

myObject.__proto__.isPrototypeOf(myObject); // => true


myObject.__proto__ returns the prototype object of myObject.

Notice that the usage of object.__proto__ as a getter/setter is not recommended. Alternatives Object.getPrototypeOf() and Object.setPrototypeOf() should be considered instead.

The good part is that ES2015 allows to use the literal __proto__ as the property name to setup the prototype right in the object literal { __proto__: protoObject }.

Let's use __proto__ property for an object initialization, and improve the bitter situation that was described in the introduction:


var myProto = {

propertyExists: function(name) {

return name in this;

},

};

var myNumbers = {

__proto__: myProto,

array: [1, 6, 7],

};

myNumbers.propertyExists('array'); // => true

myNumbers.propertyExists('collection'); // => false


myNumbers object is created with the prototype myProto using a special property name __proto__.
The object is created in a single statement, without additional functions like Object.create().

As seen, coding with __proto__ is simple. I always prefer simple and obvious solutions.

A bit out of theme. I consider an oddity that simple and flexible solutions require a big amount of work and design. If a solution is simple, you may consider that it was easy to design it. However it's vice versa:

  • To make it simple and straightforward is complicated
  • To make it complex and hard to understand is easy

If something looks too complex or not comfortable to use, probably it wasn't considered enough.
What is your opinion about simplicity? (feel free to write a comment below)

2.1 Special cases of proto usage

Even if __proto__ seems simple, there are some particular scenarios that you should be aware of.

Infographic

It is allowed to use __proto__ only once in the object literal. On duplication JavaScript throws an error:


var object = {

__proto__: {

toString: function() {

return '[object Numbers]'

}

},

numbers: [1, 5, 89],

__proto__: {

toString: function() {

return '[object ArrayOfNumbers]'

}

}

};


The object literal in the example is using two times __proto__ property, which is not allowed. An error SyntaxError: Duplicate __proto__ fields are not allowed in object literals is thrown in this situation.

JavaScript constraints to use only an object or null as a value for __proto__ property. Any attempt to use primitive types (strings, numbers, booleans) or undefined is simply ignored and does not change object's prototype.
Let's see this limitation in an example:


var objUndefined = {

__proto__: undefined,

};

Object.getPrototypeOf(objUndefined); // => {}

var objNumber = {

__proto__: 15,

};

Object.getPrototypeOf(objNumber); // => {}


The object literals are using undefined and number 15 to setup __proto__ value. Because only an object or null are allowed to be prototypes, objUndefined and objNumber still have their default prototypes: plain JavaScript objects {}. The __proto__ value is ignored.

Of course, it would be weird to attempt to use primitive types to setup object's prototype. The constraint applied here is expected.

Also be careful when the object literal has a computed property name that evaluates to '__proto__' string: { ['__proto__']: protoObj }. The property created such way does not change object's prototype, but simply creates an owned property with the key '__proto__'.

2. Shorthand method definition

It is possible to use a shorter syntax to declare methods in object literals, in a way that function keyword and : colon to be omitted. This is named shorthand method definition.

Let's define some methods using the new short form:


var collection = {

items: [],

add(item) {

this.items.push(item);

},

get(index) {

return this.items[index];

},

};

collection.add(15);

collection.add(3);

collection.get(0); // => 15


add() and get() are methods defined in collection using a short form.

A nice benefit is that methods declared this way are named functions, which is useful for debugging purposes. Executing collection.add.name from previous example returns the function name 'add'.

3. Make super calls

An interesting improvement is the ability to use super keyword as way to access inherited properties from the prototype chain. Take a look at the following example:


var calc = {

numbers: null,

sumElements() {

return this.numbers.reduce(function(a, b) {

return a + b;

});

},

};

var numbers = {

__proto__: calc,

numbers: [4, 6, 7],

sumElements() {

// Verify if numbers is not null or empty

if (this.numbers == null || this.numbers.length === 0) {

return 0;

}

return super.sumElements();

},

};

numbers.sumElements(); // => 17


calc is the prototype of numbers object. In the method sumElements of the numbers it is possible to access the methods from the prototype using super keyword: super.sumElements().
This is a method override.

Eventually super is a shortcut to access the inherited properties from the prototype chain of the object.

In the previous example you may try to call the prototype directly executing calc.sumElements(). However super.sumElements() is a correct option because it accesses the prototype chain of the object. And makes sure that sumElements() method from the prototype accesses correctly the array using this.numbers.
super presence clearly suggests that inherited properties are about to be used.

3.1 super usage restriction

super can be used only inside the shorthand method definition in an object literal.

If trying to access it from a normal method declaration { name: function() {} }, JavaScript throws an error:


var calc = {

numbers: null,

sumElements() {

return this.numbers.reduce(function(a, b) {

return a + b;

});

},

};

var numbers = {

__proto__: calc,

numbers: [4, 6, 7],

sumElements: function() {

// Verify if numbers is not null or empty

if (this.numbers == null || this.numbers.length === 0) {

return 0;

}

return super.sumElements();

},

};

// Throws SyntaxError: 'super' keyword unexpected here

numbers.sumElements();


The method sumElements is defined as a property: sumElements: function() {...}. Because super requires to be used only inside shorthand methods, calling it in such situation throws SyntaxError: 'super' keyword unexpected here.

This restriction does not affect much the way object literals are declared. Mostly is preferable to use shorthand method definitions because of a shorter syntax.

4. Computed property names

Before ES2015, the property names in object initializers were literals, mostly static strings. To create a property with calculated name, you had to use property accessors:


function prefix(prefStr, name) {

return prefStr + '_' + name;

}

var object = {};

object[prefix('number', 'pi')] = 3.14;

object[prefix('bool', 'false')] = false;

object; // => { number_pi: 3.14, bool_false: false }


Certainly, this way to define properties is by far pleasant.

Computed property names solves the problem elegantly. When evaluating the property name from an expression, place the code into square brackets {[expression]: value}. The expression evaluation result becomes the property name.

I really like the syntax: short and simple.

Let's improve the above example:


function prefix(prefStr, name) {

return prefStr + '_' + name;

}

var object = {

[prefix('number', 'pi')]: 3.14,

[prefix('bool', 'false')]: false,

};

object; // => { number_pi: 3.14, bool_false: false }


[prefix('number', 'pi')] sets the property name by evaluating prefix('number', 'pi') expression, which is 'number_pi'.
Correspondingly [prefix('bool', 'false')] sets the second property name to 'bool_false'.

4.1 Symbol as property name

Symbols also can be used as computed property names. Just make sure to include them in brackets: { [Symbol('name')]: 'Prop value' }.

For example, let's use the special property Symbol.iterator and iterate over the own property names of an object. Check the following example:


var object = {

number1: 14,

number2: 15,

string1: 'hello',

string2: 'world',

[Symbol.iterator]: function *() {

var own = Object.getOwnPropertyNames(this),

prop;

while(prop = own.pop()) {

yield prop;

}

}

}

[...object]; // => ['number1', 'number2', 'string1', 'string2']


[Symbol.iterator]: function *() { } defines a property that is used to iterate over owned properties of the object. The spread operator [...object] uses the iterator and returns the list of owned properties.

5. A look into the future: rest and spread properties

Rest and spread properties of the object literal are a proposal in draft (stage 2), which makes them a candidate for a new JavaScript version.

They are an equivalent of the spread and rest operator already available for arrays in ECMAScript 2015.

Rest properties allows to collect the properties from an object that are left after a destructuring assignment.
The following example collects the remaining properties after destructuring object:


var object = {

propA: 1,

propB: 2,

propC: 3,

};

let { propA, ...restObject } = object;

propA; // => 1

restObject; // => { propB: 2, propC: 3 }


Spread properties allows to copy into an object literal the owned properties from a source object. In this example the object literal collects into object additional properties from source object:


var source = {

propB: 2,

propC: 3,

};

var object = {

propA: 1,

...source,

};

object; // => { propA: 1, propB: 2, propC: 3 }


6. In conclusion

JavaScript is making big steps.

Even a relatively small construct as object literal was considerable improved in ECMAScript 2015. And a bunch of new features are in draft proposal.

You can setup the object's prototype directly from the initiliazer using __proto__ property name. Which is easier than dealing with Object.create().

Notice that __proto__ is a part of the annex B of the ES2015 standard, which usage is discouraged. This annex implementation is required for browsers, but optional for other environments.
NodeJS 4, 5 and 6 however support this feature.

The method declaration has now a shorter form, so you don't have to type function keyword. And inside shorthand method it's possible to use super keyword, which allows easy access to inherited properties from the prototype chain of the object.

If a property name is calculated on runtime, now you can use computed property names [expression] to initialize objects.

Indeed, object literals are now cool!