JavaScript-数据结构基础

使用数组存储数据集合

以下是数组(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'));

猜你喜欢

转载自blog.csdn.net/qq_25174701/article/details/90199219
今日推荐