js中普通对象object、map对象、set对象的区别

Object与map

  1. 一个Object的键只能是字符串或者Symbols,但是一个Map的键可以是任意值
  2. 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"]

Object.defineProperty

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相关操作
iterator相关
iterator

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}

参考

菜鸟教程中有关map
字节跳动:如何使用可迭代大部分数据类型的 for…of来遍历普通对象?
JS对象中常见的操作方法

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值