本章概要
- 对象字面量语法扩展
- 属性初始值的简写
- 对象方法的简写语法
- 可计算的属性名
- 解构赋值
- 对象解构
- 数组解构
3.6 对象字面量语法扩展
对象字面量(Object Literals)是JavaScript 中创建对象的一种非常流行的方法。在 ES6 中,通过下面的集中语法,让对象字面量变得更加强大、更加简洁。
3.6.1 属性初始值的简写
在 ES5 及早期的版本中,对象字面量只是简单的键值对集合,如下:
function createCar(color, doors){
return {
color: color,
doors: doors
}
}
createCar() 函数创建了一个对象,其属性名称与函数的参数相同,在返回的结果中,color 和 doors 分别重复了两遍,冒号左边是对象的属性名称,冒号右边是为属性赋值的变量。
另一个例子:
let name = "zhangsan"
let age = 18;
var person = {name:name,age:age};
console.log(person)
这段代码定义了一个 person对象,其属性name 和 age 的值是前面用 let 声明的变量 name 和 age。
在 ES6 中,通过使用属性初始值的简写语法,可以消除这种属性名称与本地变量之间的重复书写。当一个对象的属性与本地变量同名时,可以不写冒号和值,简单地只写属性名即可。如下:
function(color,doors){
return{
//有同名的参数,只写属性名即可
color,
doors
}
}
let name = "zhangsan";
let age = 18;
//有同名的本地变量,只写属性名即可
var person = {name,age};
当对象字面量里只有属性名称时,JavaScript引擎会在可访问作用域中查找与其同名的变量,如果找到,则该变量的值被赋给对象字面量里的同名属性。
3.6.2 对象方法的简写语法
ES6 也改进了为对象字面量定义方法的语法。
在 ES5 及早期版本中,如果为对象添加方法,则必须通过指定名称并完整定义函数来实现。如下:
var car = {
color: "red",
doors: 4,
showColor: function(){
console.log(this.color);
}
}
而在 ES6 中定义对象方法时可以省略 冒号和 function 关键字。如下:
var car = {
color: "red",
doors: 4,
showColor(){
console.log(this.color);
}
}
car.showColor();
// shouwColor
console.log(car.showColor.name);
注意:通过对象方法的简写语法创建的方法有一个name 属性,其值为圆括号前面的名称。
3.6.3 可计算的属性名
在JavaScript 中,访问对象的属性,可以通过点“.”或方括号“[]”,如果属性名包含了特殊字符或中文,或者需要通过计算得到属性名,则只能使用方括号。如下:
let suffix = "name";
let person = {};
//属性中有空格
person["first name"] = "san";
//属性名由表达式计算得到
person["last " + suffix] = "zhang";
//常规属性可以直接通过点号访问
person.age = 20;
// { 'first name': 'san', 'last name': 'zhang', age: 20 }
console.log(person);
如果采用对象字面量的语法定义对象,那么在 ES5 及早期版本中不允许出现带有表达式的属性名,而在 ES6 中,则可以在对象字面量中使用可计算的属性名称。如下:
let suffix = "name";
let person = {
["first " + suffix] : "san",
["last " + suffix]: "zhang",
age: 20
}
// { 'first name': 'san', 'last name': 'zhang', age: 20 }
console.log(person);
当然,任何可用于对象实例方括号记法的属性名,都可以作为对象字面量中的计算属性名。
3.7 解构赋值
在 JavaScript 中,经常需要从某个对象或数组中提取特定的数据赋给变量,这种操作反复且无趣。如下:
// 真实应用场景中,book对象通常是从服务器端得到的数据
let book = {
title: "Vue无难事",
isbn: "9787121362217",
price: 98,
category: {
id: 1,
name: "Web前端"
}
}
// 提取对象中的数据赋给变量
let title = book.title;
let isbn = book.isbn;
let price = book.price;
let category = book.category.name;
// 提取数组中的数据赋给变量
let arr = [1, 2, 3];
let a = arr[0], b = arr[1], c=arr[2];
ES6 为对象和数组提供了解构功能,允许按照一定模式从对象和数组中提取值,并对变量进行赋值。
3.7.1 对象解构
对象解构的语法形式是在一个赋值操作符的左侧放置一个对象字面量。如下:
let book = {
title: "Vue无难事",
isbn: "9787121362217",
price: 98
}
let {title, isbn, price} = book;
console.log(title); // Vue无难事
console.log(isbn); // 9787121362217
console.log(price); // 98
在这段代码中,book.title 的值被存储在名为 title 的变量中;另外两个也是。title、isbn和price都是本地声明的变量。
注意:如果使用 var 、let 、 或 const 声明变量,则必须提供初始化程序,即等号右侧必须提供值。以下为错误代码
let {title, isbn, price};
var {title, isbn, price}
const {title, isbn, price}
如果变量之前已经声明,之后想要用结构语法给变量赋值,那么需要用圆括号包裹整个结构赋值语句。如下:
let book = {
title: "Vue无难事",
isbn: "9787121362217",
price: 98
}
let title, isbn, price;
//{title, isbn, price} = book; // 语法错误
({title, isbn, price} = book); // 正确
JavaScript 引擎将一对开放的花括号视为一个代码块,而语法规定代码块语句不允许出现在赋值语句的左侧,添加圆括号后可以将块语句转化为一个表达式,从而实现整个解构赋值的过程。
整个解构赋值表达式的值与表达式右侧的值相等,这样,就可以实现一些有趣的操作,例如给变量赋值的同时向函数传参。如下:
let book = {
title: "Vue无难事",
isbn: "9787121362217",
price: 98
}
let title, isbn;
function outputBookInfo(book){
console.log(book);
}
// 给title、isbn变量赋值后,因解构表达式的值是=右侧的值,
// 所以此处向outputBookInfo()函数传递的参数就是book对象
outputBookInfo({title, isbn} = book);
console.log(title); // Vue无难事
console.log(isbn); // 9787121362217
使用解构赋值表达式时,如果指定的局部变量名称在对象中不存在,那么这个局部变量会被赋值为 undefined,在这种情况下,可以考虑为该变量定义一个默认值,在变量名称后添加一个等号和相应的默认值即可。如下:
let book = {
title: "Vue无难事",
isbn: "9787121362217",
price: 98
}
let {title, isbn, salesVolume = 0} = book;
console.log(title); // Vue无难事
console.log(isbn); // 9787121362217
console.log(salesVolume); // 0
当 book 对象中没有 salesVolume 属性,或者该值为 undefined 时,则使用预设的默认值。
如果希望在使用解构赋值时,使用与对象属性名不同的局部变量名,那么可以采用“属性名:局部变量名”的语法形式。如下:
let book = {
title: "Vue无难事",
isbn: "9787121362217",
price: 98
}
let {title: bookTitle, isbn: bookIsbn} = book;
console.log(bookTitle); // Vue无难事
console.log(bookIsbn); // 9787121362217
title: bookTitle 的语法含义是:读取名为 title 的属性并将其值存储到变量 bookTitle 中。需要注意的是,变量的名称在冒号右边,而左边是要读取的对象的属性名。
在 JavaScript 中,对象经常会有嵌套,而对于嵌套的对象通过解构语法取值如下:
let book = {
title: "Vue无难事",
isbn: "9787121362217",
price: 98,
category: {
id: 1,
name: "Web前端"
}
}
//let {category: {name}} = book; //局部变量名为name
let {title, isbn, category: {name: category}} = book;
console.log(title); // Vue无难事
console.log(isbn); // 9787121362217
console.log(category); // Web前端
category: {name: category} 的含义是:在找到 book对象的 category 属性后,继续深入下一层(即到 category 对象中)查找 name 属性,并将其值赋值给 category 局部变量。要注意代码中最后一条语句中的 category 是 {name: category} 中的 category。
结合前面让局部变量名与对象属性名不同的例子一起来看,可以知道,在解构语法中,冒号前的标识符代表的是对象中的检索位置,其右侧为要被赋值的变量名;如果冒号右侧是花括号,则表示要赋予的最终值嵌套在对象内部更深的层级中。
3.5节介绍了展开运算,该运算符也可以和对象解构结合使用。如下:
let person = {
name:'张三',
age:18
}
let {...newObject} = person;
let {anotherObject} = person;
let {name,age,gendar} = {...person,gendar:'男'};
console.log(newObject);
console.log(anotherObject);
console.log(name);
console.log(gendar);
let {anotherObject} = person; 表示提取person对象中的 anotherObject 属性并赋值给 anotherObject 变量,由于 person 对象没有该属性,因此为 undefined。
3.7.2 数组解构
与对象解构的语法不同,数组解构使用方括号。此外,由于数组结构本质上的不同,数组解构没有对象属性名的问题,因此语法上更加简单。如下:
let arr = [1,2,3]
let [a,b,c] = arr;
console.log(a);
console.log(b);
console.log(c);
在数组解构语法中,变量值是根据数组中元素的顺序进行选取的。如果要获取指定位置的数组元素值,可以只为该位置的元素提供变量名。例如,要获取数组中第三个位置的元素,可以采取以下代码来实现:
let arr = [1,2,3]
let [,,c] = arr;
变量c前面的逗号是前方元素的占位符,无论数组中的元素有多少个,都可以通过这种方式提取想要的元素。
如果为已声明过的变量进行数组解构赋值,不需要使用圆括号包裹解构赋值语句。如下:
let arr = [1,2,3]
let a,b,c;
[a,b,c] = arr;
也可以在数组解构赋值表达式中为数组中的任意位置添加默认值,当指定位置的元素不存在或其值为undefined时使用默认值。如下:
let arr = [1,2,3]
let [a,b,c,d=0] = arr;
嵌套数组解构与嵌套对象解构的语法类似,在原有的数组解构模式中插入另一个数组解构模式,即可将解构过程深入下一个层级。如下:
let categories = ["c++",["vue","react"],"java"];
let [language1,[,language2]] = categories;
// language1 = c++, language2 = react
展开运算符也可以和数组解构结合使用,将数组中剩余的元素赋给一个特定的变量。如下:
let arr = [1, 2, 3];
let [a, ...others] = arr;
let [...newArr] = arr; // 数组复制的另一种实现方式
console.log(a); // 1
console.log(others); // [ 2, 3 ]
console.log(others[0]) // 2
console.log(newArr); // [ 1, 2, 3 ]