Object与map
- 一个Object的键只能是字符串或者Symbols,但是一个Map的键可以是任意值
- Map中的键值是有序的(FIFO原则),而添加到对象中的键值则不是
symbol是对象属性名的另外一种表示形式,symbol声明之后是唯一的,不会产生冲突。
Symbol()函数用来创建一个symbol值
Symbol.for() 先在全局搜索,如果没有的话再去创建
Symbol.keyFor()和Symbol.for()搭配使用
Symbol是啥?详细
Object
Object遍历方式
for in: 会遍历对象中所有的可枚举属性(包括自有属性和继承属性)
for of: 会遍历对象中的value值
Object.keys(): 会返回一个包括所有的可枚举的自有属性的名称组成的数组
Object.getOwnPropertyNames(): 会返回自有属性的名称 (不管是不是可枚举的)
1、for in: 会遍历对象中所有的可枚举属性(包括自有属性和继承属性)
①for … in 循环返回的值都是数据结构的 键值名。
②遍历对象返回的对象的key值,遍历数组返回的数组的下标(key)。
③for … in 循环不仅可以遍历数字键名,还会遍历原型上的值和手动添加的其他键。
④特别情况下, for … in 循环会以看起来任意的顺序遍历键名
//for in 用来遍历对象,可以拿到对象的属性名;由于普通对象的属性名是没有前后顺序的,所以使用for in拿到的key也是没有顺序的,这个顺序是由浏览器决定的
//for in 由于拿到的key是字符串,所以并不是很适合遍历数组,但是也还可以用。
const obj = { a: 1, b: 2, c: 3 };
for (let prop in obj) {
console.log(prop, obj[prop]);
}
// Output:
// a 1
// b 2
// c 3
const obj = {
itemA: 'itemA',
itemB: 'itemB'
}
// 使用Object.create创建一个原型为obj的对象 (模拟继承来的属性)
var newObj = Object.create(obj)
newObj.newItemA = 'newItemA'
newObj.newItemB = 'newItemB'
for(i in newObj){
console.log(i)
}
// newItemA
// newItemB
// itemA
// itemB
// 现在我们将其中的一个属性变为不可枚举属性
Object.defineProperty(newObj, 'newItemA', {
enumerable: false
})
for(i in newObj){
console.log(i)
}
// newItemB
// itemA
// itemB
如果不想让for…in枚举继承来的属性可以借助Object.prototype.hasOwnProperty()
obj.hasOwnProperty(“key”) //obj表示对象,结果为false表示不包含;否则表示包含// 接上例 for(i in newObj){ if( newObj.hasOwnProperty(i) ) console.log(i) } //newItemA newItemB
2、for of: 对可迭代数据结构进行遍历
for of的特点
①for of循环用来获取一对键值对的值,而for in 获取的是 键名
②一个数据结构只要部署了Symbol.iterator属性,就被视为具有iterator接口,就可以使用for of进行遍历
③对于普通的对象,没有Symbol.iterator这个属性,所以使用for of回报obj is not iterable
④for of不同于forEach,它可以与break、continue和return配合使用,也即是说for of循环可以随时退出循环。
⑤for of提供了遍历所有数据结构的统一接口
哪些数据结构部署了Symbol.iterator属性了呢?
只要有iterator接口的数据结构,都可以使用for of 循环
- 数组Array
- Map(映射)
- Set(集合)
- String(字符串)
- arguments对象
- Nodelist对象,就是获取的dom列表集合
- generator
以上这些都可以直接使用 for of 循环。 凡是部署了 iterator 接口的数据结构也都可以使用数组的 扩展运算符(…)、和解构赋值等操作。
{
// 迭代字符串
const iterable = 'ES6';
for (const value of iterable) {
console.log(value);
}
// Output:
// "E"
// "S"
// "6"
}
{
// 迭代数组
const iterable = ['a', 'b'];
for (const value of iterable) {
console.log(value);
}
// Output:
// a
// b
}
{
// 迭代Set(集合)
const iterable = new Set([1, 2, 2, 1]);
for (const value of iterable) {
console.log(value);
}
// Output:
// 1
// 2
}
{
// 迭代Map
const iterable = new Map([["a", 1], ["b", 2], ["c", 3]]);
for (const entry of iterable) {
console.log(entry);
}
// Output:
// ["a", 1]
// ["b", 2]
// ["c", 3]
for (const [key, value] of iterable) {
console.log(value);
}
// Output:
// 1
// 2
// 3
}
{
// 迭代Arguments Object(参数对象)
function args() {
for (const arg of arguments) {
console.log(arg);
}
}
args('a', 'b');
// Output:
// a
// b
}
{
// 迭代生成器
function* foo(){
yield 1;
yield 2;
yield 3;
};
for (let o of foo()) {
console.log(o);
}
// Output:
// 1
// 2
// 3
}
- 可以看出,for of可以迭代大部分对象甚至字符串,却不能遍历普通对象。
// 普通对象
const obj = {
foo: 'value1',
bar: 'value2'
}
for(const item of obj){
console.log(item)
}
// Uncaught TypeError: obj is not iterable
- 如何用for…of迭代普通对象
通过前面的基本用法,我们知道,for…of可以迭代数组、Map等数据结构,顺着这个思路,我们可以结合对象的Object.values()、Object.keys()、Object.entries()方法以及解构赋值的知识来用for…of遍历普通对象【但是显然,这不是本文的终极方案,终极方案见下文】。
//keys values entries 方法返回一个新的 Iterator 对象
const obj = {
foo: 'value1',
bar: 'value2'
}
// 打印由value组成的数组
console.log(Object.values(obj)) // ["value1", "value2"]
// 打印由key组成的数组
console.log(Object.keys(obj)) // ["foo", "bar"]
// 打印由[key, value]组成的二维数组
// copy(Object.entries(obj))可以把输出结果直接拷贝到剪贴板,然后黏贴
console.log(Object.entries(obj)) // [["foo","value1"],["bar","value2"]]
const obj = {
foo: 'value1',
bar: 'value2'
}
// 方法一:使用for of迭代Object.entries(obj)形成的二维数组,利用解构赋值得到value
for(const [, value] of Object.entries(obj)){
console.log(value) // value1, value2
}
// 方法二:Map
// 普通对象转Map
// Map 可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组
console.log(new Map(Object.entries(obj)))
// 遍历普通对象生成的Map
for(const [, value] of new Map(Object.entries(obj))){
console.log(value) // value1, value2
}
// 方法三:继续使用for in
for(const key in obj){
console.log(obj[key]) // value1, value2
}
{
// 方法四:将【类数组(array-like)对象】转换为数组
// 该对象需具有一个 length 属性,且其元素必须可以被索引。
const obj = {
length: 3, // length是必须的,否则什么也不会打印
0: 'foo',
1: 'bar',
2: 'baz',
a: 12 // 非数字属性是不会打印的
};
const array = Array.from(obj); // ["foo", "bar", "baz"]
for (const value of array) {
console.log(value);
}
// Output: foo bar baz
}
{
// 方法五:给【类数组】部署数组的[Symbol.iterator]方法【对普通字符串属性对象无效】
const iterable = {
0: 'a',
1: 'b',
2: 'c',
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
console.log(item); // 'a', 'b', 'c'
}
}
3、Object.keys(): 会返回一个包括所有的可枚举的自有属性的名称组成的数组
Object.keys() 返回一个数组,其元素是字符串,对应于直接在对象上找到的可枚举的字符串键属性名。这与使用 for…in 循环迭代相同,只是 for…in 循环还会枚举原型链中的属性。Object.keys() 返回的数组顺序和与 for…in 循环提供的顺序相同。
// 接上例 同下面的map
const result = Object.keys(newObj)
console.log(result) // ["newItemA","newItemB"]
- Object.getOwnPropertyNames(): 会返回自有属性的名称 (不管是不是可枚举的)
const arr = ["a", "b", "c"];
console.log(Object.getOwnPropertyNames(arr).sort())
// ["0", "1", "2", "length"]
// 类数组对象
const obj = { 0: "a", 1: "b", 2: "c"};
console.log(Object.getOwnPropertyNames(obj).sort())
// ["0", "1", "2"]
map对象
map对象的基本操作
let map = new Map()
map.has(key) //判断map对象中是否有key这个键,如果有返回true,否则返回false
map.size //获取map对象中的成员个数
map.set(key,value)
map.get(key)
map.delete(key)
map是可迭代的,map.keys()返回一个新的迭代对象,map.keys().next()获取迭代对象的第一个值,如果再去next()那么获取第二个值,map.keys().next().value 用来获取map对象的第一个成员的key
map对象遍历
forEach()
map.forEach((key,val)=>{
//操作
}
)
for of 遍历
var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
// 将会显示两个 log。 一个是 "0 = zero" 另一个是 "1 = one"
for (var [key, value] of myMap) {
console.log(key + " = " + value);
}
for (var [key, value] of myMap.entries()) {
console.log(key + " = " + value);
}
/* 这个 entries 方法返回一个新的 Iterator 对象,它按插入顺序包含了 Map 对象中每个元素的 [key, value] 数组。 */
// 将会显示两个log。 一个是 "0" 另一个是 "1"
for (var key of myMap.keys()) {
console.log(key);
}
/* 这个 keys 方法返回一个新的 Iterator 对象, 它按插入顺序包含了 Map 对象中每个元素的键。 */
// 将会显示两个log。 一个是 "zero" 另一个是 "one"
for (var value of myMap.values()) {
console.log(value);
}
/* 这个 values 方法返回一个新的 Iterator 对象,它按插入顺序包含了 Map 对象中每个元素的值。 */
Set对象
Set不允许有重复的值
数组去重
var mySet = new Set([1, 2, 3, 4, 4]);
[...mySet]; // [1, 2, 3, 4]
并集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var union = new Set([...a, ...b]); // {1, 2, 3, 4}
交集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var intersect = new Set([...a].filter(x => b.has(x))); // {2, 3}
差集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var difference = new Set([...a].filter(x => !b.has(x))); // {1}