JS 数据处理 - 对象和数组
《JS 数据处理 - 对象和数组》
对象
对象内容读取
如果属性键为字符串,且该字符串中只包含英文字母和下划线的话,可以直接用 <obj>.<key>
来读取属性值。
const essay = {
title: '基本数据处理 - 对象和数组',
content: ['对象', '数组'],
from: {
title: '基本数据处理',
author: {
name: 'tmac',
description: '全栈开发',
skill: [ 'Web 开发', '移动端开发', '小程序开发' ]
}
},
}
essay.title // 基本数据处理 - 对象和数组
essay.from.author.name // 阿梦
而当对象中所需要读取的目标属性键为数字、包含英文字母和下划线以外的字符串甚至是 Symbol
对象的时候,就需要使用 obj[key]
的形式来读取属性值了。
const obj = {
1: 2,
'a b c': 'd e f',
[Symbol.for('foo')]: 'bar'
}
obj[1] //=> 2
obj['a b c'] //=> d e f
obj[Symbol.for('foo')] //=> bar...
修改对象内容
在 JavaScript 中存在着“引用”和“值”的概念区别,当然这同样不是本书的讨论范围。简单地解释,就是对对象内容进行修改跟进行读取类似,只是在读取语句后面加上 = <new value>
即可。
const obj = {
foo: 'bar',
1: 2,
'a b c': 'd e f',
[Symbol.for('foo')]: 'bar'
}
obj.foo = 'rab'
obj[1] = 3
obj.foo // rab
obj[1] // 3
当然,当你需要为一个对象添加新的属性时,也是通过同样的方式添加属性。
const obj = {}
obj.foo = 'bar'
obj[1] = 2
但要非常注意的是,在一般情况下,无论是对对象进行添加、读取还是修改属性,都遵循着嵌套链完整的原则,具体如下例所示。
const obj = {
item: {}
}
obj.item.foo = 'bar' // 正确
obj.something.bar = 1 // 错误
处理对象的一些常见方法
1. 对象的深拷贝
调用JSON.parse(JSON.stringify(obj))
来实现对象obj
的复制,也可以使用 Object.assign(target, …sources)
来拷贝
let obj = { a: 'apple' }
let objCopy1 = JSON.parse(JSON.stringify(obj)
let objCopy2 = Object.assign({}, obj)
let objCopy3 = {...obj}
obj.a = 'banana'
obj.a // 'banana'
objCopy1.a // 'apple'
objCopy2.a // 'apple'
objCopy3.a // 'apple'
2. 对象的合并
ES5 中增加了原生的 Object.assign(target, …sources)
来实现合并。而利用 ES6 中的扩展运算符,调用形如{…x, …y}
的声明,也能实现对象的合并。
let obj1 = { a: 'apple' }
let obj2 = { b: 'banana' }
let obj3 = { c: 'orange' }
Object.assign(obj1, obj2 , obj3)
Object.assign({}, obj1, obj2 , obj3)
{...obj1, ...obj2, ...obj3}
// {a: "apple", b: "banana", c: "orange"}
3. Object.keys(obj) 的用法
const arr = ['a', 'b', 'c']
Object.keys(arr) // ['0', '1', '2']
const obj = { 0: 'a', 1: 'b', 2: 'c' };
Object.keys(obj) // ['0', '1', '2']
const obj2 = { name: 'tony', sex: 'male', age: 25 };
Object.keys(obj2) // ["name", "sex", "age"]
const anObj = { 100: 'a', 2: 'b', 7: 'c' };
Object.keys(anObj) // ['2', '7', '100']
const myObj = Object.create({}, {
getFoo: {
value: () => this.foo
}
})
myObj.foo = 1
console.log(Object.keys(myObj)) // ['foo']
也可用于 Vue
中将组件批量挂载到全局
const components = {
AppHeader,
AppBody,
AppFooter
}
const install = (Vue) => {
Object.keys(components).forEach((key) => {
Vue.component(key, components[key])
})
}
Vue.use({...components, install})
4. Object.entries() 的用法
Object.entries()
方法返回一个给定对象自身可枚举属性的键值对数组
const object1 = { foo: 'bar', baz: 42 }
Object.entries(object1)[1] // ["baz", 42]
const object2 = { 0: 'a', 1: 'b', 2: 'c' }
Object.entries(object2)[2] // ["2", "c"]
const object3 = { 100: 'a', 2: 'b', 7: 'c' }
Object.entries(object3)[0] // ["2", "b"]
Object.entries(object3)[1] // ["7", "c"]
数组
数组类型监测
instanceof
只有一个全局作用域下,使用这种方法。若网页中包含多个框架,容易出错。
const arr = ["a","b","c"]
arr instanceof Array // true
arr instanceof Object // true
Array.isArray()
不管有几个全局环境,都可以,但是兼容性不高。
Array.isArray([1, 2, 3]) // true
Array.isArray({foo: 123}) // false
Array.isArray("foobar") // false
Array.isArray(undefined) // false
Object.prototype.toString.call()
使用对象的toString
函数判断,兼容性好。不能使用数组自身的toString
,因为该函数已经被重写了。
const arr = ["a","b","c"]
Object.prototype.toString.call(arr) // "[object Array]"
处理数组的一些常用方法
1. 数组转为字符串
const arr = ["a","b","c"]
arr.toLocaleString() // "a,b,c"
arr.toString() // "a,b,c"
arr.join(',') // "a,b,c"
arr.valueOf() // 返回本身 ["a", "b", "c"]
...arr // a b c
2. 其他数据结构转为数组
Array.from(obj, mapFn, thisArg)
方法有一个可选参数mapFn
,让你可以在最后生成的数组上再执行一次map
方法后再返回。也就是说Array.from(obj, mapFn, thisArg)
就相当于Array.from(obj).map(mapFn, thisArg)
Array.from('foo') // ["f", "o", "o"]
Array.from([1, 2, 3], x => x + x) // [2, 4, 6]
Array.of()
将一组值转换为数组
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
3. 数组的添加和删除 (会改变原数组)
- 栈方法
arr.push(el1, ..., elN)
将一个或N个元素添加到数组的末尾,并返回新数组的长度 ```js let arr = [“a”,“b”,“c”]
arr.push(“d”) // 返回 4,数组改变为 [“a”,“b”,“c”,“d”] arr.push(“d”,“e”) // 返回 5, [“a”,“b”,“c”,“d”,“e”]
- 栈方法 `arr.pop()` 从数组中删除最后一个元素,并返回该元素的值
```js
let arr = ["a","b","c"]
arr.pop() // 返回 "c",数组改变为 ["a","b"]
- 队列方法
arr.shift()
从数组中删除第一个元素,并返回该元素的值 ```js let arr = [“a”,“b”,“c”]
arr.shift() // 返回 “a”,数组改变为 [“b”,“c”]
- 队列方法 `arr.unshift(el1, ..., elN)` 将一个或 N 个元素添加到数组的开头,并返回新数组的长度
```js
let arr = ["a","b","c"]
arr.unshift("-1") // 返回 4,数组改变为 ["-1","a","b","c"]
arr.unshift("-2","-1") // 返回 5,["-2","-1","a","b","c"]
4. 数组的排序 (会改变原数组)
arr.reverse()
方法将数组中元素的位置颠倒 ```js let arr = [“a”,“b”,“c”]
arr.reverse() // 数组改变为 [“c”,“b”,“a”]
- `arr.sort()` 方法用原地算法对数组的元素进行排序,并返回数组。排序不一定是稳定的。默认排序顺序是根据字符串`Unicode`码点。
```js
const months = ['March', 'Jan', 'Feb', 'Dec']
months.sort() // ["Dec", "Feb", "Jan", "March"]
const numbers = [1, 30, 4, 21]
months.sort() // [1, 21, 30, 4]
5. 数组的合并
- 扩展运算符
...
const arr1 = ['a', 'b', 'c']
const arr2 = ['d', 'e', 'f']
[...arr1, ...arr2] // ['a', 'b', 'c', 'd', 'e', 'f']
arr1.concat(arr2)
合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组
const arr1 = ['a', 'b', 'c']
const arr2 = ['d', 'e', 'f']
arr1.concat(arr2) // ['a', 'b', 'c', 'd', 'e', 'f']
6. 数组的切割、截取 slice()
arr.slice(begin, end)
方法返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象。此方法不会更改现有数组,而是返回一个新数组。
let arr = ["a","b","c","d","e"]
arr.slice(2) // ["c","d","e"]
arr.slice(0, 2) // ["a","b"]
arr.slice(3, 4) // ["d"]
7. 数组的拼接 (会改变原数组)
arr.splice(start, deleteCount, items)
方法:
- 第一个参数start
表示起始位置
- 第二个参数deleteCount
表示要删除的个数(若为0,表示不删除)
- 第三个参数items
表示要添加的项(可选,可以传多个)
- 会改变原数组
- 该方法经常用来做前后互换的排序
let arr = ["a","b","c","d","e"]
arr.splice(1,0,"666") // ["a","666","b","c","d","e"]
arr.splice(4,1,"888") // ["a","666","b","c","d","888"]
8. 数组的填充 fill()
arr.fill(content, start, end)
方法,使用给定值,填充一个数组:
- 第一个参数 content
表示填充的值
- 第二个参数 start
表示填充起始位置
- 第三个参数 end
表示填充的结束位置的前一个
- 常用于接口数据模拟
['a', 'b', 'c'].fill(7) // [7, 7, 7]
new Array(3).fill(7) // [7, 7, 7]
['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c']
9. 查找项的位置 indexOf
lastIndexOf
arr.indexOf(sth)
从前往后查找,返回查找项的位置,没有的话返回-1arr.lastIndexOf(sth)
从后往前查找,返回查找项的位置,没有的话返回-1
10. 数组的累加 & 聚合 reduce()
arr.reduce(callback)
方法对累加器和数组中的每个元素(从左到右)应用一个函数,将其简化为单个
const arr = [ 1, 2, 3, 4, 5 ]
// 求和 => 15
arr.reduce((a, b) => a + b)
// 求积 => 120
arr.reduce((a, b) => a * b)
11. 数组的查找和过滤
arr.find(callback)
方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。
const arr = [5, 12, 8, 130, 44]
arr.find((item) => item > 10) // 12
arr.findIndex(callback)
方法返回数组中满足提供的测试函数的第一个元素的索引index。否则返回 -1。
const arr = [5, 12, 8, 130, 44]
arr.findIndex((item) => item > 10) // 1
arr.some(callback)
方法测试数组中的某些元素是否通过由提供的函数实现的测试。返回Boolean值。
const arr = [5, 12, 8, 130, 44]
arr.some((item) => item > 10) // true
arr.every(callback)
方法测试数组的所有元素是否都通过了指定函数的测试。
const arr = [5, 12, 8, 130, 44]
arr.every((item) => item > 10) // false
arr.includes(value)
方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。
const arr = [5, 12, 8, 130, 44]
arr.includes(5) // true
arr.filter(callback)
方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。不更改原数组。
const arr = [5, 12, 8, 130, 44]
arr.filter((item) => item < 100) // [5, 12, 8, 44]
12. 数组的循环 forEach()
arr.forEach()
方法对数组的每个元素执行一次提供的函数
let arr = ['a', 'b', 'c']
arr.forEach((item) => {
console.log(item);
})
// expected output: "a"
// expected output: "b"
// expected output: "c"
13. 数组的遍历 map()
arr.map()
方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果
let arr = [
{
age: 14,
name: "小红"
},
{
age: 18,
name: "小明"
},
{
age: 22,
name: "老王"
}
]
arr.map(item => item.age*2) // [28, 36, 44]
arr.map(item => item.name) // ["小红", "小明", "老王"]