本文探讨了JavaScript中的对象文字可能实现的功能,尤其是根据最近的ECMAScript更新。
使用文字符号创建JavaScript对象的功能非常强大。 ES2015(ES6)引入的新功能使在所有现代浏览器(非IE)和Node.js中的对象处理更加轻松。
如果必须先声明一个class
然后才能实现任何事情,则使用某些语言创建对象在开发时间和处理能力方面可能会非常昂贵。 在JavaScript中,可以轻松地动态创建对象。 例如:
// ES5-compatible code
var myObject = {
prop1: 'hello',
prop2: 'world',
output: function() {
console.log(this.prop1 + ' ' + this.prop2);
}
};
myObject.output(); // hello world
一次性使用的对象被广泛使用。 示例包括配置设置,模块定义,方法参数,函数的返回值等。ES2015(ES6)添加了一系列功能来增强对象文字。
通过变量进行对象初始化
对象的属性通常是由具有相同名称的变量创建的。 例如:
// ES5 code
var
a = 1, b = 2, c = 3;
obj = {
a: a,
b: b,
c: c
};
// obj.a = 1, obj.b = 2, obj.c = 3
ES6中无需进行讨厌的重复!
// ES6 code
const
a = 1, b = 2, c = 3;
obj = {
a
b
c
};
// obj.a = 1, obj.b = 2, obj.c = 3
当使用显示模块模式时 ,这对于返回的对象很有用,该模块模式 (有效地)使用命名空间代码以避免命名冲突。 例如:
// ES6 code
const lib = (() => {
function sum(a, b) { return a + b; }
function mult(a, b) { return a * b; }
return {
sum,
mult
};
}());
console.log( lib.sum(2, 3) ); // 5
console.log( lib.mult(2, 3) ); // 6
您可能已经看到它在ES6模块中使用了:
// lib.js
function sum(a, b) { return a + b; }
function mult(a, b) { return a * b; }
export { sum, mult };
对象方法定义速记
ES5中的对象方法需要function
语句。 例如:
// ES5 code
var lib = {
sum: function(a, b) { return a + b; },
mult: function(a, b) { return a * b; }
};
console.log( lib.sum(2, 3) ); // 5
console.log( lib.mult(2, 3) ); // 6
ES6中不再需要此功能。 它允许以下速记语法:
// ES6 code
const lib = {
sum(a, b) { return a + b; },
mult(a, b) { return a * b; }
};
console.log( lib.sum(2, 3) ); // 5
console.log( lib.mult(2, 3) ); // 6
在此不可能使用ES6粗箭头=>
函数语法,因为该方法需要一个名称。 也就是说,如果直接命名每个方法(例如ES5),则可以使用箭头功能。 例如:
// ES6 code
const lib = {
sum: (a, b) => a + b,
mult: (a, b) => a * b
};
console.log( lib.sum(2, 3) ); // 5
console.log( lib.mult(2, 3) ); // 6
动态属性键
在ES5中,虽然可以在创建对象之后添加变量,但是不能使用变量作为键名称。 例如:
// ES5 code
var
key1 = 'one',
obj = {
two: 2,
three: 3
};
obj[key1] = 1;
// obj.one = 1, obj.two = 2, obj.three = 3
通过在[
方括号]
放置表达式,可以在ES6中动态分配对象键。 例如:
// ES6 code
const
key1 = 'one',
obj = {
[key1]: 1,
two: 2,
three: 3
};
// obj.one = 1, obj.two = 2, obj.three = 3
任何表达式都可以用来创建密钥。 例如:
// ES6 code
const
i = 1,
obj = {
['i' + i]: i
};
console.log(obj.i1); // 1
动态键可用于方法和属性。 例如:
// ES6 code
const
i = 2,
obj = {
['mult' + i]: x => x * i
};
console.log( obj.mult2(5) ); // 10
是否应该创建动态属性和方法是另一回事。 该代码可能难以阅读,因此创建对象工厂或类可能更可取。
解构(对象属性中的变量)
通常有必要将对象的属性值提取到另一个变量中。 必须在ES5中明确声明。 例如:
// ES5 code
var myObject = {
one: 'a',
two: 'b',
three: 'c'
};
var
one = myObject.one, // 'a'
two = myObject.two, // 'b'
three = myObject.three; // 'c'
ES6支持解构:您可以创建与等效对象属性同名的变量。 例如:
// ES6 code
const myObject = {
one: 'a',
two: 'b',
three: 'c'
};
const { one, two, three } = myObject;
// one = 'a', two = 'b', three = 'c'
也可以使用符号{ propertyName: newVariable }
将属性分配给任何名称的变量。 例如:
// ES6 code
const myObject = {
one: 'a',
two: 'b',
three: 'c'
};
const { one: first, two: second, three: third } = myObject;
// first = 'a', second = 'b', third = 'c'
带有嵌套数组和子对象的更复杂对象也可以在解构分配中引用。 例如:
// ES6 code
const meta = {
title: 'Enhanced Object Literals',
pageinfo: {
url: 'https://www.sitepoint.com/',
description: 'How to use object literals in ES2015 (ES6).',
keywords: 'javascript, object, literal'
}
};
const {
title : doc,
pageinfo: { keywords: topic }
} = meta;
/*
doc = 'Enhanced Object Literals'
topic = 'javascript, object, literal'
*/
最初看起来很复杂,但请记住在所有解构任务中:
- 分配的左侧是解构源 -包含要提取的数据的数组或对象
- 分配的右侧是销毁目标 -定义要分配的变量的模式。
有很多警告。 您不能以大括号开头的语句,因为它看起来像一个代码块。 例如:
{ a, b, c } = myObject; // FAILS
您必须声明变量,例如:
const { a, b, c } = myObject; // WORKS
或如果已经声明了变量,则使用括号,例如:
let a, b, c;
({ a, b, c } = myObject); // WORKS
因此,您应注意不要混用已声明和未声明的变量。
在许多情况下,对象分解很有用。
默认功能参数
将单个对象传递给函数通常比使用一长串参数要容易得多。 例如:
prettyPrint( {
title: 'Enhanced Object Literals',
publisher: {
name: 'SitePoint',
url: 'https://www.sitepoint.com/'
}
} );
在ES5中,有必要解析对象以确保设置了适当的默认值。 例如:
// ES5 assign defaults
function prettyPrint(param) {
param = param || {};
var
pubTitle = param.title || 'No title',
pubName = (param.publisher && param.publisher.name) || 'No publisher';
return pubTitle + ', ' + pubName;
}
在ES6中,我们可以为任何参数分配默认值。 例如:
// ES6 default value
function prettyPrint(param = {}) { ... }
然后,我们可以使用解构来提取值并在必要时分配默认值:
// ES6 destructured default value
function prettyPrint(
{
title: pubTitle = 'No title',
publisher: { name: pubName = 'No publisher' }
} = {}
) {
return `${pubTitle}, ${pubName}`;
}
您是否发现此代码更易于阅读是另一回事!
解析返回的对象
函数只能返回一个值,但它可能是具有数百个属性和/或方法的对象。 在ES5中,必须获取返回的对象,然后相应地提取值。 例如:
// ES5 code
var
obj = getObject(),
one = obj.one,
two = obj.two,
three = obj.three;
ES6的解构使此过程更简单,并且不需要将对象保留为变量:
// ES6 code
const { one, two, three } = getObject();
您可能已经在Node.js代码中看到了类似的分配。 例如,如果仅需要文件系统( fs
)方法readFile
和writeFile
,则可以直接引用它们。 例如:
// ES6 Node.js
const { readFile, writeFile } = require('fs');
readFile('file.txt', (err, data) => {
console.log(err || data);
});
writeFile('new.txt', 'new content', err => {
console.log(err || 'file written');
});
ES2018(ES9)剩余/扩展属性
在ES2015中,rest参数和散点运算符三点( ...
)表示法仅适用于数组。 ES2018为对象启用了类似的休息/扩展功能。 一个基本的例子:
const myObject = {
a: 1,
b: 2,
c: 3
};
const { a, ...x } = myObject;
// a = 1
// x = { b: 2, c: 3 }
您可以使用该技术将值传递给函数:
restParam({
a: 1,
b: 2,
c: 3
});
function restParam({ a, ...x }) {
// a = 1
// x = { b: 2, c: 3 }
}
您只能在声明的末尾使用单个rest属性。 此外,它仅适用于每个对象的顶层,而不适用于子对象。
传播算子可以在其他对象中使用。 例如:
const
obj1 = { a: 1, b: 2, c: 3 },
obj2 = { ...obj1, z: 26 };
// obj2 is { a: 1, b: 2, c: 3, z: 26 }
您可以使用散布运算符来克隆对象( obj2 = { ...obj1 };
),但是请注意,您只会得到浅表副本。 如果一个属性包含另一个对象,则克隆将引用相同的对象。
ES2018(ES9)的rest / spread属性支持不完整,但在Chrome,Firefox和Node.js 8.6+中可用。
对象文字一直很有用。 ES2015引入的新功能并未从根本上改变JavaScript的工作方式,但它们节省了键入工作,并导致了更清晰,更简洁的代码。
From: https://www.sitepoint.com/es6-enhanced-object-literals/