【译】Object与Map的异同及使用场景

栏目: JavaScript · 发布时间: 5年前

内容简介:这是介绍Array,Set,Object,Map系列的第二篇译文。原文链接:戳这里按照惯例,详细的API补充在在文章底部。

这是介绍Array,Set,Object,Map系列的第二篇译文。

原文链接:戳这里

按照惯例,详细的API补充在在文章底部。

【译】Object与Map的异同及使用场景

你可能想问,为什么要单独将Object和Map进行对比,而不是对比Map,Array,或是Object和Set?不同于其它两组,Map和Object有非常多相似的地方需要我们去更深入的了解和对比,才能分析出他们分别更适合的应用场景。

概念

什么是Map

Map是一种数据结构(它很特别,是一种抽象的数据结构类型),数据一对对进行存储,其中包含键以及映射到该键的值。并且由于键的唯一性,因此不存在重复的键值对。

Map便是为了快速搜索和查找数据而生的。

例如: {(1, "smile"), (2, "cry"), (42, "happy")}

在Map中,每一对数据的格式都为键值对的形式。

注:Map中的键和值可以是任何数据类型,不仅限于字符串或整数。

什么是Object

JavaScript中的 常规对象 是一种字典类型的数据结构——这意味着它依然遵循与Map类型相同键值对的存储结构。Object中的key,或者我们可以称之为属性,同样是独一无二的并且对应着一个单独的value。

另外,JavaScript中的Object拥有内置原型(prototype)。需要注意的是,JavaScript中几乎所有对象都是Object实例,包括Map。

例如: {1: 'smile', 2: 'cry', 42: 'happy'}

从定义上来看,Object和Map的本质都是以键值对的方式存储数据,但实质上他们之间存在很大的区别——

  • 键:Object遵循普通的字典规则,键必须是单一类型,并且只能是整数、字符串或是Symbol类型。但在Map中,key可以为任意数据类型(Object, Array等)。(你可以尝试将一个对象设置为一个Object的key,看看最终的数据结构)
  • 元素顺序:Map会保留所有元素的顺序,而Object并不会保证属性的顺序。(如有疑问可参考:链接)
  • 继承:Map是Object的实例对象,而Object显然不可能是Map的实例对象。
var map = new Map([[1,2],[3,4]]);
console.log(map instanceof Object); //true
var obj = new Object();
console.log(obj instanceof Map); //false
复制代码

如何构建

Object

与数组相似,定义一个Object的方式非常简单直接:

var obj = {}; //空对象
var obj = {id: 1, name: "Test object"}; 
//2 keys here: id maps to 1, and name maps to "Test object"
复制代码

或使用构造方法:

var obj = new Object(); //空对象
var obj = new Object; //空对象
复制代码

或者使用 Object.prototype.create

var obj = Object.create(null); //空对象
复制代码

注:

你只能在某些特定的情况下使用 Object.prototype.create ,比如:

  • 你希望继承某个原型对象,而无需定义它的构造函数。
var Vehicle = {
    type: "General",
    display: function(){console.log(this.type);}
}
var Car = Object.create(Vehicle); //创建一个继承自Vehicle的对象Car
Car.type = "Car";  //重写type属性
Car.display(); //Car
Vehicle.display(); //General
复制代码

在通常情况下,与数组相似,尽量避免使用构造函数的方式,理由如下:

  • 构造函数会写更多代码
  • 性能更差
  • 更加混乱更容易引起程序错误,例如:
var obj = new Object(id: 1, name: "test") //显然的语法错误

var obj1 = {id: 1, name: "test"};
var obj2 = new Object(obj1); //obj1与obj2指向同一个对象
obj2.id = 2;
console.log(obj1.id); //2
复制代码

Map

创建Map只有一种方式,就是使用其内置的构造函数以及 new 语法。

var map = new Map(); //Empty Map
var map = new Map([[1,2],[2,3]]); // map = {1=>2, 2=>3}
复制代码

语法:

Map([iterable])

Map的构造函数接收一个数组或是一个可遍历的对象作为参数,这个参数内的数据都为键值对结构。如果是数组,则包含两个元素 [key, value]

访问元素

  • 对于Map,获取元素要通过方法 Map.prototype.get(key) 实现,这意味着我们必须先知道该值所对应的key
map.get(1);
复制代码
  • Object类似,要获取到值必须先知道所对应的key/property,不过使用不同的语法: Object.<key> and Object[‘key’]
obj.id //1
obj['id'] //1
复制代码
  • 判断Map中是否存在某个key
map.has(1);//return boolean value:  true/false
复制代码
  • Object则需要一些额外的判断
var isExist = obj.id === undefined; 

// or
var isExist = 'id' in obj; // 该方法会检查继承的属性
复制代码

Map与Object语法很相似,不过Map的语法更简单。

注:我们可以使用 Object.prototype.hasOwnProperty() 判断Object中是否存在特定的key,它的返回值为 true/false ,并且 只会检查对象上的非继承属性

插入元素

  • Map支持通过 Map.prototype.set() 方法插入元素,该方法接收两个参数:key,value。如果传入已存在的key,则将会重写该key所对应的value。
map.set(4,5); 
复制代码
  • 同样,为Object添加属性可以使用下面的方法
obj['gender'] = 'female'; //{id: 1, name: "test", gender: "female"}
obj.gender = male; // 重写已存在的属性
//{id: 1, name: "test", gender: "male"}
复制代码

正如你所看到的,归功于其数据结构,两种插入元素方法的时间复杂度都为O(1),检索key并不需要遍历所有数据。

删除元素

Object并没有提供删除元素的内置方法,我们可以使用 delete 语法:

delete obj.id;
复制代码

值得注意的是,很多人提出使用一下方法是否会更好,更节约性能。

obj.id = undefined
复制代码

这两种方式在逻辑上有很大差别:

  • delete 会完全删除Object上某个特有的属性
  • 使用 obj[key] = undefined 只会改变这个key所对应的value为 undefined ,而该属性仍然保留在对象中。

因此在使用 for...in... 循环时仍然会遍历到该属性的key。

当然,检查Object中是否已存在某属性将在这两种情况下产生两种不同的结果,但以下检查除外:

obj.id === undefined; //结果相同
复制代码

因此,性能提升在某些情况下并不适合。

还有一点, delete 操作符的返回值为 true/false ,但其返回值的依据与预想情况有所差异:

对于所有情况都返回 true ,除非属性是一个 non-configurable 属性,否则在非严格模式返回 false ,严格模式下将抛出异常。

Map有更多内置的删除元素方式,比如:

  • delete(key) 用于从Map中删除特定key所对应的value,该方法返回一个布尔值。如果目标对象中存在指定的key并成功删除,则返回 true ;如果对象中不存在该key则返回 false
var isDeleteSucceeded = map.delete(1);
console.log(isDeleteSucceeded); //true- 
复制代码
  • clear() ——清空Map中所有元素。
map.clear();
复制代码

Object要实现Map的 clear() 方法,需要遍历这个对象的属性,逐个删除。

Object和Map删除元素的方法也非常相似。其中删除某个元素的时间复杂度为O(1),清空元素的时间复杂度为O(n),n为Object和Map的大小。

获取大小

与Object相比,Map的一个优点是它可以自动更新其大小,我们可以通过以下方式轻松获得:

console.log(map.size);
复制代码

而使用Object,我们需要通过 Object.keys() 方法计算其大小,该方法返回一个包含所有key的数组。

console.log(Object.keys(obj).length);
复制代码

元素的迭代

Map有内置的迭代器,Object没有内置的迭代器。

补充:如何判断某种类型是否可迭代,可以通过以下方式实现

//typeof <obj>[Symbol.iterator] === “function”
console.log(typeof obj[Symbol.iterator]); //undefined
console.log(typeof map[Symbol.iterator]); //function
复制代码

在Map中,所有元素可以通过 for...of 方法遍历:

//For map: { 2 => 3, 4 => 5 }
for (const item of map){
    console.log(item); 
    //Array[2,3]
    //Array[4,5]
}
//Or
for (const [key,value] of map){
    console.log(`key: ${key}, value: ${value}`);
    //key: 2, value: 3
    //key: 4, value: 5
}
复制代码

或者使用其内置的 forEach() 方法:

map.forEach((value, key) => console.log(`key: ${key}, value: ${value}`));
//key: 2, value: 3
//key: 4, value: 5
复制代码

但对于Object,我们使用 for...in 方法

//{id: 1, name: "test"}
for (var key in obj){
   console.log(`key: ${key}, value: ${obj[key]}`);
   //key: id, value: 1
   //key: name, value: test
}
复制代码

或者使用 Object.keys(obj) 只能获取所有key并进行遍历

Object.keys(obj).forEach((key)=> console.log(`key: ${key}, value: ${obj[key]}`));
//key: id, value: 1
//key: name, value: test
复制代码

好的,问题来了,因为它们在结构和性能方面都非常相似,Map相比Object具有更多的优势,那我们是否应该更常使用Map代替Object?

Object和Map的应用场景

尽管,Map相对于Object有很多优点,依然存在某些使用Object会更好的场景,毕竟Object是JavaScript中最基础的概念。

get()
var obj = {
    id: 1, 
    name: "It's Me!", 
    print: function(){ 
        return `Object Id: ${this.id}, with Name: ${this.name}`;
    }
}
console.log(obj.print());//Object Id: 1, with Name: It's Me.
复制代码

(你可以使用Map进行尝试,然而Map并不能实现这样的数据结构)

delete

总结

如何选择Object和Map取决于你要使用的数据类型以及操作。

当我们只需要一个简单的可查找存储结构时,Map相比Object更具优势,它提供了所有基本操作。但在任何意义上,Map都不能替代Object。因为在Javascript中,Object毕竟不仅仅是一个普通的哈希表(因此Object不应该用作普通哈希表,它会浪费很多资源)。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

A Philosophy of Software Design

A Philosophy of Software Design

John Ousterhout / Yaknyam Press / 2018-4-6 / GBP 14.21

This book addresses the topic of software design: how to decompose complex software systems into modules (such as classes and methods) that can be implemented relatively independently. The book first ......一起来看看 《A Philosophy of Software Design》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试