Why is the literal volume of JavaScript objects cool?

Source: Internet
Author: User
Before ECMAScript2015, the object literal volume (also called the object initiator) function in JavaScript was weak. It can only define two attributes: normal key-value pairs {name1: value} Getters & amp; n...

Prior to ECMAScript 2015, the object literal volume (also called the object initializer) in JavaScript was weak. It can only define two types of attributes:

  • Normal key/value pair {name1: value}

  • Getters {get name () {...} and setters {set name (val) {...} are used to set and obtain the value to be calculated.

Sadly, all the usage of the object literal volume can be covered by only one simple example:

Try in JS Bin

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. When it comes to object creation, structure, and access prototype, the language must provide a simple structure.

Defining an object and setting its prototype is a common task. I always think that the prototype should be directly supported by the object literal, using a single syntax.

Unfortunately, the literal limitation makes it impossible to have a direct solution. You have to use Object. create () to combine the Object literal volume and set the prototype:

Try in JS Bin

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, this is an uncomfortable solution. JavaScript is based on the prototype. Why is it so troublesome to create an object from the prototype?

Fortunately, JavaScript is changing. Many frustrating problems are being solved step by step in JavaScript.

This article explains how ES2015 solves the problems mentioned above and improves the literal size of objects for additional benefits:

  • Configure the prototype during Object Construction

  • Shorthand method definition

  • Call the parent Method

  • Calculation attribute name

At the same time, let's look into the future and get to know the latest proposal (stage 2): Object rest attributes and Attribute Expansion operators.

1. Set the prototype during Object Construction

As you know, one of the methods to access a prototype of an existing object is to use the getter attribute _ proto __:

Try in JS Bin

var myObject = {    name: 'Hello World!' };myObject.__proto__; // => {}  myObject.__proto__.isPrototypeOf(myObject); // => true

MyObject. _ proto _ return the prototype object of myObject.

The good news is that ES2015 allows the literal _ proto _ as the attribute name to set the prototype of the object literal {_ proto __: protoObject }.

Let's rewrite the above example with _ proto _ to make it look better:

Try in JS Bin

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

The myNumbers object is created using the prototype myProto, which can be implemented through the special attribute _ proto.

This Object is created using a simple statement without additional functions such as Object. create ().

As you can see, using _ proto _ is simple. I prefer simple and direct solutions.

Let's get back to the topic. I think that a simple and reliable solution requires a lot of design and practice. If a solution is simple, you may think it is also easy to design, but it is not like this:

  • The process of making it simple and clear is complex.

  • Make it complex and hard to understand but easy to understand

If something looks too complex or uncomfortable to use, it is likely that its designers are not careful.

Yuan Fang, what do you think? (You are welcome to post comments at the bottom of the article for discussion)

2.1 Special case of using _ proto _

Although _ proto _ seems simple, you need to pay special attention to some special scenarios.

In the object literal, _ proto _ is only allowed once. If you use JavaScript for multiple times, an exception is thrown:

Try in JS Bin

var object = {    __proto__: {    toString: function() { return '[object Numbers]' }  },  numbers: [1, 5, 89],  __proto__: {    toString: function() { return '[object ArrayOfNumbers]' }  }};

The _ proto _ attribute is used twice for the objects in the preceding example. This is not allowed. In this case, a SyntaxError: Duplicate _ proto _ fields are not allowed in object literals will be thrown.

JavaScript only allows the use of object or null as the value of the _ proto _ attribute. Other native types (such as strings, values, and Boolean types) or undefined are ignored and the object prototype cannot be changed.

Let's look at an example:

Try in JS Bin

var objUndefined = {    __proto__: undefined }; Object.getPrototypeOf(objUndefined); // => {}  var objNumber = {    __proto__: 15 }; Object.getPrototypeOf(objNumber); // => {}

In the preceding example, the value of _ proto _ is set using undefined and Value 15. Because only objects or null can be used, objUndefined and objNumber are still their default prototypes: simple JavaScript objects {}. _ Proto _ is ignored.

Of course, it is strange to try to use the native type to set the object prototype. Therefore, the restrictions here are as expected.

2. shorthand method definition

Now, you can use a shorter syntax to declare a method in the object literal volume. The function keyword and colon are omitted. This is called the shorthand method definition ).

Let's define some methods in a new way:

Try in JS Bin

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 using shortcuts in collection.

A good thing is that the declared method is named, which is helpful for debugging. Execute collection. add. name to return the function name 'add '.

3. Call the parent class Method

An interesting improvement is the ability to use the super keyword to access attributes inherited from the prototype chain. See the following example:

Try in JS Bin

var calc = {    sumArray (items) { return items.reduce(function(a, b) { return a + b;    });  }}; var numbers = {    __proto__: calc,  numbers: [4, 6, 7],  sumElements() { return super.sumArray(this.numbers);  }};numbers.sumElements(); // => 17

Calc is the property of the numbers object. In the sumElements method of numbers, to call the method on the prototype calc, you can use the super Keyword: super. sumArray ().

Therefore, super is a quick way to access the inherited attributes from the prototype chain.

In the previous example, we can also directly call cale. sumArray (), but super is a better choice because it accesses the prototype chain of the object. Its existence clearly implies that the inherited attributes will be used.

3.1 super restrictions

In the literal volume of an object, super can only be used in the shorthand method definition.

If you use it in the general method declaration {name: function () {}, JavaScript throws an exception:

Try in JS Bin

var calc = {    sumArray (items) { return items.reduce(function(a, b) { return a + b;    });  }}; var numbers = {    __proto__: calc,  numbers: [4, 6, 7],  sumElements: function() { return super.sumArray(this.numbers);  }}; // Throws SyntaxError: 'super' keyword unexpected here numbers.sumElements();

In the above Code, the method sumElements is defined as: sumElements: function (){...}. Because super is required to be used in stenography, calling super will throw an exception: SyntaxError: 'super' keyword unexpected here.

This limit does not have much impact on Object literal declaration, because in most cases, we have no reason not to use the shorthand method definition. After all, its syntax is simpler.

4. Calculate the attribute name

Before ES2015, the attribute name of the object initializer was a literal character string in most cases. To create a dynamic computing attribute name, you have to use the attribute accessors:

Try in JS Bin

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 }

Of course, this method of defining attributes is not satisfactory.

Computing attribute names can solve this problem more elegantly.

When we calculate the attribute name from the expression, place the code between square brackets {[expression]: value }. The calculation result of this expression will be the attribute name.

I really like this syntax: short and simple.

Let's improve the above Code:

Try in JS Bin

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 ')] You can set the attribute name by calculating the prefix ('number', 'Pi') expression. The result is 'Number _ pi '.

Correspondingly, [prefix ('bool ', 'false')] sets the second attribute name to 'boolean _ false '.

4.1 As the attribute name

Symbols can also be used to calculate the attribute name. You only need to include it in square brackets: {[Symbol ('name')]: 'prop value '}.

For example, you can use the special attribute Symbol. iterator to iterate over an object's own attribute name. The Code is as follows:

Try in JS Bin

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 an attribute to iterate over the attributes of an object. Expand the operator [... object] to use the iterator and return the list of its own attributes.

5. outlook for the future: rest and attributes

Object literal Rest and Attribute Expansion are a proposal in the new standard draft (stage 2), meaning this feature is a candidate for the new version of JavaScript specifications.

The array expansion and rest operators have been implemented.

The Rest attribute allows us to use objects to collect attributes from the left side of the deconstruct value assignment. See the following example:

Try in JS Bin

var object = {    propA: 1,  propB: 2,  propC: 3 }; let {propA, ...restObject} = object;  propA; // => 1  restObject; // => { propB: 2, propC: 3 }

Property expansion allows you to copy the attributes of the source object to the object literal. In the preceding example, the object literally collects additional attributes from the souce object.

Try in JS Bin

var source = {    propB: 2,  propC: 3 }; var object = {    propA: 1,  ...source}object; // => { propA: 1, propB: 2, propC: 3 }
6. Conclusion

JavaScript is improving rapidly.

Even a relatively small structure, such as the object literal volume, has been greatly improved in ES2015, not to mention a lot of new features in the draft.

You can use the _ proto _ attribute in the initialization tool to directly set the Object prototype, which is more convenient than using Object. create.

The method declaration can be written in a shorter form, so that you do not need to write the function keyword. Then, the super keyword can be used in the stenography method to conveniently access the attributes on the inherited prototype chain.

If an attribute name is calculated at runtime, you can use the calculated attribute name [expression] to initialize the object.

Indeed, the object literal volume is cool now!

What do you think? Comments below are welcome to participate in the discussion.

The above is why I want to say that JavaScript objects are literally cool content. For more information, see the PHP Chinese website (www.php1.cn )!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.