An in-depth analysis of object literals in JavaScript

青灯夜游
Release: 2021-02-24 10:14:49
forward
2104 people have browsed it

This article will take you to understand the object literals in JavaScript and analyze why object literals are cool. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to everyone.

An in-depth analysis of object literals in JavaScript

BeforeECMAScript 2015, object literals (also called object initializers) in Javascript were quite simple. They could define two types of properties. :

  • Pairs of static property names and values{ name1: value1 }
  • Throughgetters{ get name() {..} }andsetters{ set name(val){..} }Defined dynamically calculated property values

Unfortunately, a simple example can represent all the possibilities of object literals:

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
Copy after login

JS is a languagebased onprototypes, so everything is an object. It is necessary to provide an easily constructible language for object creation, configuration, and access to prototypes.

Defining an object and setting its prototype is a common task. The best way is to set the prototype directly in the object literal using a statement.

Unfortunately, the limitations of literals do not allow a simple solution to achieve this. You must useobject.create()with an object literal to set the prototype.

var myProto = { propertyExists: function(name) { return name in this; } }; var myNumbers = Object.create(myProto); myNumbers['arrat'] = [1, 6, 7]; myNumbers.propertyExists('array'); // => true myNumbers.propertyExists('collection'); // => false
Copy after login

I think this solution is not flexible enough. JS is based on prototypes. Why is it so troublesome to create objects using prototypes?

Fortunately, JavaScript is also slowly improving. Many of the rather uncomfortable features of JS are being addressed step by step.

This article demonstrates how ES2015 solves the problems described above and adds features to improve the capabilities of object literals:

  • Set the prototype in the object constructor
  • Shorthand method declaration
  • PerformsuperCall
  • Computable property name

In addition, we can Looking ahead, take a look at the new proposals in (Draft 2): Collectable and expandable properties.

An in-depth analysis of object literals in JavaScript

1. Set the prototype in the object constructor

As you already know, there is a way to access the prototype of a created object The way is to reference the__proto__getter attribute:

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

myObject.__proto__Returns the prototype object ofmyObject.

Please note that it is not recommended to useobject.__ proto__as agetter/setter. Alternatives should be considered usingObject.getPrototypeOf()andObject.setPrototypeOf().

The good news is thatES2015 allows you to use__proto__as a property name in an object literal{ __proto__: protoObject }to set the prototype.

Let's initialize the object with__proto__properties to see how it improves on the unintuitive solution 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
Copy after login

myNumbersis using The object is created with the special attribute name__proto__, and its prototype ismyProto. This object is created with a simple declaration, without using additional functions likeObject.create().

As you can see, coding using__proto__is simple. I usually recommend simple and intuitive solutions.

As an aside, I think it’s a bit strange that simple and scalable solutions rely on a lot of design and work. If a solution is simple, you might think it is easy to design. However, the truth is exactly the opposite:

  • Making things simple and direct is very complicated
  • Making things complicated and difficult to understand is easy

If some things look If it seems complicated or difficult to use, it may not have been fully thought out. What do you think about returning to nature? (Feel free to leave a comment)

1.1 The user manual of__proto__under special circumstances

Even though__proto__looks very concise , there are some specific scenarios you need to pay attention to.

An in-depth analysis of object literals in JavaScript

对象字面量中__proto__只允许使用一次。重复使用 JS 会抛出异常:

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

上面示例中的对象字面量使用了两次__proto__属性,这是不允许的。在这种情况下,将在会抛出SyntaxError: Duplicate __proto__ fields are not allowed in object literals的语法错误。

JS 约束只能用一个对象或null作为__proto__属性值。任何使用原始类型(字符串,数字,布尔值)或undefined类型都将被忽略,并且不会更改对象的原型。

让我们看看这个限制的例子:

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

这个对象字面量使用了undefined和数字15来设置__proto__的值。因为只有对象或null允许被当做原型,objUndefinedobjNumber仍然拥有他们默认的原型: JavaScript 空对象{}__proto__的值被忽略了。

当然,尝试用原始类型去设置对象的原型会挺奇怪。这里的约束符合预期。

2. 速写式方法声明

可以使用较短的语法在对象常量中声明方法,以省略function关键字和:冒号的方式。它被称之为速写式方法声明

接着,让我们使用速写的方法来定义一些方法吧:

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
Copy after login

add()get()collection里使用这个缩写形式定义的方法。

这个方法声明的方式还一个好处是它们都是非匿名函数,这在调试的时候会很方便。 上个例子执行collection.add.name返回函数名'add'

3. 进行super调用

JS 一个有趣的改进是可以使用super关键字来访问原型链中父类的属性。看下面的例子:

var calc = { numbers: null, sumElements() { return this.numbers.reduce(function(a, b) { return a + b; }); }, }; var numbers = { __proto__: calc, numbers: [4, 6, 7], sumElements() { if (this.numbers == null || this.numbers.length === 0) { return 0; } return super.sumElements(); }, }; numbers.sumElements(); // => 17
Copy after login

calcnumbers对象的原型。在numberssumElements方法中,可以通过super关键字调用原型的super.sumArray()方法。

最终,super是从对象原型链访问继承的属性的快捷方式。

在前面的示例中,可以尝试直接执行calc.sumElements()来调用原型。 然而,super.sumElements()可以正确调用,因为它访问对象的原型链。并确保原型中的sumElements()方法使用this.numbers正确访问数组。

super存在清楚地表明继承的属性将被使用。

3.1super的使用限制

super在对象字面量中只能在速写式方法声明里使用。

如果尝试从普通方法声明{ name: function() {} }访问它,JS 将抛出一个错误:

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() { if (this.numbers == null || this.numbers.length === 0) { return 0; } return super.sumElements(); }, }; // Throws SyntaxError: 'super' keyword unexpected here numbers.sumElements();
Copy after login

这个sumElements方法被定义为一个属性:sumElements: function() {...}, 因为super只能在速写式方法声明中使用。所以,在这种情况下调用它会抛出SyntaxError: 'super' keyword unexpected here的语法错误。

此限制在很大程度上不影响对象字面量的声明方式。 多数情况下因为语法更简洁,使用速写式方法声明会更好。

4. 可计算的属性名

在 ES2015 之前, 对象初始化使用的是字面量的形式,通常是静态字符串。要创建具有计算名称的属性,就必须使用属性访问器。

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 }
Copy after login

当然,这种定义属性的方式到目前为止令人愉快。

计算属性名称可以很好地解决该问题。当你要通过某个表达式计算属性名时,在方括号{[expression]: value}里替换对应的代码。对应的表达式会把计算结果作为属性名。

我非常喜欢这个语法:简短又简洁。

让我们改进上面的例子:

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 }
Copy after login

[prefix('number', 'pi')]通过计算prefix('number', 'pi')表达式设置了'number_pi'这个属性名。

相应地,[prefix('bool', 'false')]将第二个属性名称设置为'bool_false'

4.1Symbol作为属性名

Symbols也可以作为可计算的属性名。只要确保将它们包括在方括号中即可:{ [Symbol('name')]: 'Prop value' }

例如,让我们用Symbol.iterator这个特殊的属性,去遍历对象的自有属性名。如下所示:

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']
Copy after login

[Symbol.iterator]: function *() { }定义一个属性,该属性用于迭代对象的自有属性。展开操作符[...object]使用了迭代器来返回自有属性的数组。

5. 对未来的一个展望: 可收集可展开的属性

对象字面量的可收集可展开的属性目前是草案第二阶段 (stage 2) 中的一个提议,它将被选入下一个 Javascript 版本。

它们等价于 ECMAScript 2015 中已可用于数组的展开和收集操作符

可收集的属性允许收集一个对象在解构赋值后剩下的属性们。

下面这个例子收集了object解构后留下的属性:

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

可展开的属性允许从一个源对象拷贝它的自有属性到另一个对象字面量中。这个例子中对象字面量的其它属性合集是从source对象中展开的:

var source = { propB: 2, propC: 3, }; var object = { propA: 1, ...source, }; object; // => { propA: 1, propB: 2, propC: 3 }
Copy after login

6. 总结

JavaScript 正在迈出重要的一步。

在ECMAScript 2015中,即使是作为对象字面量的相对较小的结构也得到了相当大的改进。提案草案中还包含了许多新功能。

你可以在对象初始化时直接通过__proto__属性名设置其原型。比用Object.create()简单很多。

请注意,__proto__是 ES2015 标准附件B的一部分,不鼓励使用。 该附件实现对于浏览器是必需的,但对于其他环境是可选的。NodeJS 4、5和6支持此功能。

现在方法声明有个更简洁的模式,所以你不必输入function关键字。而且在速写式声明里,你可以使用super关键字,它允许你十分容易得通过对象的原型链访问父类属性。

如果属性名需要在运行时计算,现在你可以用可计算的属性名[expression]来初始化对象。

对象字面量现在确实很酷!

英文原文地址:https://dmitripavlutin.com/why-object-literals-in-javascript-are-cool/

作者:Dmitri Pavlutin

译文地址:https://segmentfault.com/a/1190000020669949

更多编程相关知识,请访问:编程视频!!

The above is the detailed content of An in-depth analysis of object literals in JavaScript. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:segmentfault.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!