文章目录
使用数组存储数据集合
以下是数组(Array)数据结构的最简单的实现例子。这是一个一维数组(one-dimensional array),它只有一层,或者说在它里面没有包含其它的数组结构。它里面包含了布尔值(booleans)、字符串(strings)、数字(numbers)以及一些其他的 JavaScript 语言中合法的数据类型:
let simpleArray = ['one', 2, 'three’, true, false, undefined, null];
console.log(simpleArray.length);
// 输出 7
所有数组都有一个长度(length)属性。可以使用Array.length方法来访问它。
下面是一个多维数组(multi-dimensional Array),或者说是一个包含了其他数组的数组。在它的内部还包含了 JavaScript 中的对象(objects)结构。
let complexArray = [
[
{
one: 1,
two: 2
},
{
three: 3,
four: 4
}
],
[
{
a: "a",
b: "b"
},
{
c: "c",
d: “d”
}
]
];
let yourArray = ["a", 2, true, "c", null, {name: "john"}];
使用方括号访问数组的内容
先定义一个包含 3 个元素的数组:
let ourArray = ["a", "b", "c"];
在一个数组结构中,其内部的每个元素都有一个与之对应的索引(index)。JavaScript 数组的索引是从0开始的。
要从一个数组中获取一个元素,我们可以在一个数组变量名的后面加一个使用“方括号”括起来的索引。这叫做方括号符号(bracket notation)。
例如我们要从ourArray数组变量中获取数据元素"a"并将其赋值给一个变量,我们可以编写如下所示的代码:
let ourVariable = ourArray[0];
// ourVariable 的值为 "a"
除了使用 “索引” 来获取某个元素值以外,还可以通过类似的方法来设置一个索引位置所对应的元素值:
ourArray[1] = "not b anymore";
// ourArray 现在的值为 ["a", "not b anymore", "c"];
利用方括号将索引为 1 的元素从"b"设置为了"not b anymore"。
使用 push() 和 unshift() 添加项目到数组中
push()方法将元素插入到一个数组的末尾
unshift()方法将元素插入到一个数组的开头。
请看以下例子:
let twentyThree = 'XXIII';
let romanNumerals = ['XXI', 'XXII'];
romanNumerals.unshift('XIX', 'XX');
// 数组现在为 ['XIX', 'XX', 'XXI', 'XXII']
romanNumerals.push(twentyThree);
// 数组现在为 ['XIX', 'XX', 'XXI', 'XXII', 'XXIII']
使用 pop() 和 shift() 从数组中删除项目
pop()从数组的末尾移除一个元素
shift()从数组的开头移除一个元素。
pop()和shift()与对应的push()和unshift()的关键区别在于,前者不能接受输入参数,而且每次只能修改数组中的一个元素。
看以下的例子:
let greetings = ['whats up?', 'hello', 'see ya!'];
greetings.pop();
// 数组现在等于 ['whats up?', 'hello']
greetings.shift();
// 数组现在等于 ['hello']
对于上述两个方法中的任意一个,我们都可以返回被其移除的元素:
let popped = greetings.pop();
// 返回 'hello'
// greetings 现在等于 []
例子:
function popShift(arr) {
let popped = arr.pop();
let shifted = arr.shift();
return [shifted, popped]; //返回["challenge", "complete"]
}
console.log(popShift(['challenge', 'is', 'not', 'complete']));
使用 splice()
删除项目
splice()可以从数组中的任意位置移除任意数量的连续的元素。
splice()最多可以接受 3 个参数,splice()接收的前两个参数基于调用splice()数组中元素的索引。
splice()的第一个参数代表从数组中的哪个索引开始移除元素,而第二个参数指示要从数组中删除多少个元素。例如:
let array = ['today', 'was', 'not', 'so', 'great'];
array.splice(2, 2);
// 从第 3 个元素开始,删除 2 个元素
// 现在该数组等于 ['today', 'was', 'great']
splice()不仅从被调用的数组中移除元素,还会返回一个包含被移除元素的数组:
let array = ['I', 'am', 'feeling', 'really', 'happy'];
let newArray = array.splice(3, 2);
// newArray 等于 ['really', 'happy']
function sumOfTen(arr) {
arr.splice(1, 2)
return arr.reduce((a, b) => a + b); //返回10
}
console.log(sumOfTen([2, 5, 1, 5, 2, 1]));
增加项目
除了移除元素,还可以利用它的第三个参数来向数组中添加元素。第三个参数可以是一个或多个元素,这些元素会被添加到数组中。这能够便捷地将数组中的一个或一系列元素换成其他的元素。例如在一个数组中存储了一系列 DOM 元素的配色,并希望基于某些行为动态地改变一个颜色:
function colorChange(arr, index, newColor) {
arr.splice(index, 1, newColor);
return arr;
}
let colorScheme = ['#878787', '#a08794', '#bb7e8c', '#c9b6be', '#d1becf'];
colorScheme = colorChange(colorScheme, 2, '#332327');
// 我们移除了 '#bb7e8c' 并在其位置上添加了 '#332327'
// colorScheme 现在等于 ['#878787', '#a08794', '#332327', '#c9b6be', '#d1becf']
这个函数接受一个十六进制值(hex value)的数组、要被移除的元素的索引以及要替换旧元素的新颜色作为输入参数。它的返回值是一个含有被修改的新的配色的数组。
例子:
function htmlColorNames(arr) {
arr.splice(0, 2, "DarkSalmon", "BlanchedAlmond");
return arr;
}
console.log(htmlColorNames(['DarkGoldenRod', 'WhiteSmoke', 'LavenderBlush', 'PaleTurqoise', 'FireBrick']));
//返回["DarkSalmon", "BlanchedAlmond", "LavenderBlush", "PaleTurqoise", "FireBrick"]。
复制数组
使用 slice() 拷贝数组项目
slice()并不修改数组,而是复制或者说提取(extract)给定数量的元素到一个新数组里,而调用方法的数组则保持不变。
slice()只接受 2 个输入参数—第一个是开始提取元素的位置(索引),第二个是结束提取元素的位置(索引)。slice 方法会提取直到该索引的元素,但被提取的元素不包括该索引对应的元素。
请看以下例子:
let weatherConditions = ['rain', 'snow', 'sleet', 'hail', 'clear'];
let todaysWeather = weatherConditions.slice(1, 3);
// todaysWeather 等于 ['snow', 'sleet'];
// weatherConditions 仍然等于 ['rain', 'snow', 'sleet', 'hail', 'clear']
从一个已有的数组中提取了一些元素,并用这些元素创建了一个新数组。
function forecast(arr) {
return arr.slice(2, 4); //返回["warm", "sunny"]
}
console.log(forecast(['cold', 'rainy', 'warm', 'sunny', 'cool', 'thunderstorms']));
使用扩展运算符复制数组
slice()已经能让我们从一个数组中选择一些元素来复制到新数组中了,而 ES6 中又新引入了一个简洁且可读性强的语法展开运算符(spread operator),它能让我们方便地复制数组中的所有元素。展开语法是这样的:…
在实践中,我们可以这样用展开运算符来复制一个数组:
let isArray = [true, true, undefined, false, null];
let thatArray = [...thisArray];
// thatArray 等于 [true, true, undefined, false, null]
// thisArray 保持不变,并等于 thatArray
例子:
function copyMachine(arr, num) {
let newArr = [];
while (num >= 1) {
newArr.push([...arr]);
num--;
}
return newArr;
}
console.log(copyMachine([true, false, true], 2));
组合使用数组和扩展运算符
展开运算符的另一个大用处是合并数组,或者将某个数组的所有元素插入到另一个数组的任意位置。用传统的语法我们也可以连接两个数组,但只能两个数组首尾相接。而展开语法能使下面的操作变得极其简单:
let thisArray = ['sage', 'rosemary', 'parsley', 'thyme'];
let thatArray = ['basil', 'cilantro', ...thisArray, 'coriander'];
// thatArray 现在等于 ['basil', 'cilantro', 'sage', 'rosemary', 'parsley', 'thyme', 'coriander']
使用展开语法,我们这样就实现了一个用传统方法要写得很复杂冗长的操作。
使用 indexOf() 检查元素是否存在
由于数组可以在任意时间被修改或者说被改变(mutated),不能保证某个数据在一个给定数组中的位置,甚至不能保证该元素还存在于该数组中。幸运的是,JavaScript 提供了另一个内置方法indexOf()。这个方法可以便捷地检查某个元素是否存在于一个数组中。
indexOf()方法接受一个元素作为输入参数,并返回该元素在数组中的位置(索引);若该元素不存在于数组中则返回-1。
例如:
let fruits = ['apples', 'pears', 'oranges', 'peaches', 'pears'];
fruits.indexOf('dates') // 返回 -1
fruits.indexOf('oranges') // 返回 2
fruits.indexOf('pears') // 返回 1,即第一个出现的 'pears' 元素在数组中的索引为 1
function quickCheck(arr, elem) {
return arr.indexOf(elem) >=0 ? true : false;
}
console.log(quickCheck(['squash', 'onions', 'shallots'], 'mushrooms'));
使用 For 循环迭代数组的所有项
在进行与数组有关的编程时,有时需要遍历数组的所有元素来找出我们需要的元素,或者对数组执行特定的操作。JavaScript 提供了几个内置的方法,它们以不同的方式遍历数组来获得不同的结果(如every()、forEach()、map()等等)。而简单的for循环不仅能实现这些功能,而且相比之下也更灵活。
请看以下例子:
function greaterThanTen(arr) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] > 10) {
newArr.push(arr[i]);
}
}
return newArr;
}
greaterThanTen([2, 12, 8, 14, 80, 0, 1]);
// 返回 [12, 14, 80]
这个函数使用一个for循环来遍历一个数组,逐一对其中的元素进行测试。我们用这个方法简单地以编程的方式找出了数组中大于10的元素,并返回了一个包含这些元素的数组。
function filteredArray(arr, elem) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
if(arr[i].indexOf(elem) == -1){
newArr.push(arr[i]);
}
}
return newArr;
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));//返回[ ]
//filteredArray([[10, 8, 3], [14, 6, 23], [3, 18, 6]], 18)应该返回[ [10, 8, 3], [14, 6, 23] ]
创建复杂的多维数组
数组中的数组还可以包含其他数组,数组中是可以嵌套任意层的数组的。从而数组可以被用来实现非常复杂的叫做多维(multi-dimensional)或嵌套(nested)数组。
请看如下例子:
let nestedArray = [ // 顶层,或第 1 层——最外层的数组
['deep'], // 数组中的数组,第 2 层
[
['deeper'], ['deeper'] // 第 3 层嵌套的两个数组
],
[
[
['deepest'], ['deepest'] // 第 4 层嵌套的两个数组
],
[
[
['deepest-est?'] // 第 5 层嵌套的一个数组
]
]
]
];
虽然这个例子看起来错综复杂,但这样复杂的数组并不算罕见,尤其是在处理大量数据的时候。
但我们仍能简单地用方括号符号来访问到嵌套得最深的数组:
console.log(nestedArray[2][1][0][0][0]);
// 输出:deepest-est?
既然我们知道数据在哪里,我们就能修改它:
nestedArray[2][1][0][0][0] = 'deeper still';
console.log(nestedArray[2][1][0][0][0]);
// 现在输出:deeper still
let myNestedArray = [
['unshift', false, 1, 2, 3, 'complex', 'nested'],
['loop', 'shift', 6, 7, 1000, 'method'],
['concat', false, true, 'spread', 'array',['deep']],
['mutate', 1327.98, 'splice', 'slice', 'push',[['deeper']]],
['iterate', 1.3849, 7, '8.4876', 'arbitrary', 'depth',[[['deepest']]]]
];
将键值对添加到对象中
对象(object)本质上是键值对(key-value pair)的集合,或者说,一系列被映射到唯一标识符(叫做属性(property)或者键(key))的数据。
看一个很简单的例子:
let FCC_User = {
username: 'awesome_coder',
followers: 572,
points: 1741,
completedProjects: 15
};
上面的代码定义了一个叫做FCC_User的对象,它有 4 个属性,每个属性映射一个特定的值。如果我们想知道FCC_User有多少followers,我们可以这样访问其followers属性:
let userData = FCC_User.followers;
// userData 等于 572
这叫做点符号(dot notation)。我们还可以用方括号符号来访问对象中的属性:
let userData = FCC_User['followers']
// userData 等于 572
注意,在用方括号符号时,我们在括号里写的是字符串followers(用引号括起)。方括号符号让我们能用一个变量作为属性名来访问对象的属性。
若我们在方括号中不写引号而直接写followers,JavaScript 引擎会将其看作一个变量,并抛出一个ReferenceError: followers is not defined的错误。
let foods = {
apples: 25,
oranges: 32,
plums: 28
};
foods['bananas'] = 13;
foods.grapes = 35;
foods.strawberries = 27;
console.log(foods);
修改嵌套在对象中的对象
对象中也可以嵌套任意层的对象。对象的属性值可以是 JavaScript 支持的任意类型,包括数组和其他对象。
请看以下例子:
let nestedObject = {
id: 28802695164,
date: 'December 31, 2016',
data: {
totalUsers: 99,
online: 80,
onlineStatus: {
active: 67,
away: 13
}
}
};
nestedObject有 3 个唯一的键:值为一个数字的id、值为一个字符串的date和值为一个嵌套了其他对象的对象的data。
let userActivity = {
id: 23894201352,
date: 'January 1, 2017',
data: {
totalUsers: 51,
online: 42
}
};
userActivity.data.online = 45; // userActivity["data"]["online"] = 45;
console.log(userActivity);
使用方括号访问属性名称
假设一个超市的收银台的程序中使用了一个foods对象,并且有一些程序逻辑会设置selectedFood,我们需要查询foods对象来检查某种食物是否存在,我们可以这样写检查逻辑:
let selectedFood = getCurrentFood(scannedItem);
let inventory = foods[selectedFood];
上述代码会先计算selectedFood变量的值,并返回foods对象中以该值命名的属性对应的值,若没有以该值命名的属性则会返回undefined。有时候对象的属性名在运行之前是不确定的,或者我们需要动态地访问对象的属性,这时方括号符号就会很有用。
let foods = {
apples: 25,
oranges: 32,
plums: 28,
bananas: 13,
grapes: 35,
strawberries: 27
};
function checkInventory(scannedItem) {
return foods[scannedItem];
}
console.log(checkInventory("apples"));
//checkInventory("apples")应该返回25
使用 delete 关键字删除对象属性
从一个对象中移除一个键值对。如果我们想移除apples属性,我们可以使用delete关键字:
delete foods.apples;
检查对象是否具有某个属性
如果我们想知道一个对象中是否含有某个属性呢?JavaScript 为我们提供了两种不同的方式来实现这个功能,一个是hasOwnProperty()方法,另一个是in关键字。
如果我们有一个users对象,它有一个Alan属性,我们可以用以下两种方式之一来检查该属性在对象中是否存在:
users.hasOwnProperty('Alan');
'Alan' in users;
// 都返回 true
let users = {
Alan: {
age: 27,
online: true
},
Jeff: {
age: 32,
online: true
},
Sarah: {
age: 48,
online: true
},
Ryan: {
age: 19,
online: true
}
};
function isEveryoneHere(obj) {
return users.hasOwnProperty('Alan','Jeff','Sarah','Ryan') ? true : false;
}
console.log(isEveryoneHere(users));
使用 for…in 语句迭代对象
有时候你需要遍历一个对象中的所有键。这需要 JavaScript 中的一个特殊语法:for…in 语句。以遍历 users对象的键为例:
for (let user in users) {
console.log(user);
};
// 输出:
Alan
Jeff
Sarah
Ryan
在这个语句中,我们定义了一个user变量,你可以看到,这个变量在 for…in 语句对对象的每一个键的遍历中都会被重置。
注意: 跟数组不同,对象中的键是无序的,因此一个对象中某个键的位置,或者说它出现的相对顺序,在引用或访问该键时是不确定的。
let users = {
Alan: {
age: 27,
online: false
},
Jeff: {
age: 32,
online: true
},
Sarah: {
age: 48,
online: false
},
Ryan: {
age: 19,
online: true
}
};
function countOnline(obj) {
var num = 0;
for(let user in obj) {
obj[user].online === true ? num++ : num;
}
return num; //2
}
console.log(countOnline(users));
使用 Object.Keys() 生成对象所有键组成的数组
可以输入一个对象作为参数来调用Object.keys()方法,使其生成一个包含对象中所有键的数组。
这会返回一个由对象中所有键的名称(字符串)组成的数组。
注意:这个数组中的项的顺序是不确定的。
let users = {
Alan: {
age: 27,
online: false
},
Jeff: {
age: 32,
online: true
},
Sarah: {
age: 48,
online: false
},
Ryan: {
age: 19,
online: true
}
};
function getArrayOfUsers(obj) {
return Object.keys(obj);
}
console.log(getArrayOfUsers(users));
var anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj)); // console: ['2', '7', '100']
修改存储在对象中的数组
JavaScript 对象的所有运算。你可以增加、修改和移除键值对,检查某个键是否存在,并且遍历一个对象中的所有键。
let user = {
name: 'Kenneth',
age: 28,
data: {
username: 'kennethCodesAllDay',
joinDate: 'March 26, 2016',
organization: 'freeCodeCamp',
friends: [
'Sam',
'Kira',
'Tomo'
],
location: {
city: 'San Francisco',
state: 'CA',
country: 'USA'
}
}
};
function addFriend(userObj, friend) {
userObj.data.friends.push(friend);
return userObj.data.friends; //返回["Sam", "Kira", "Tomo", "Pete"]
}
console.log(addFriend(user, 'Pete'));