Map vs Object trong javascript - khi nào nên sử dụng ?

Nội dung bài viết

Map là gì? Nghe có vẻ đơn giản, vì mỗi lập trình viên đều nghe về "map" rất nhiều. Nhưng để hiểu nó thì cũng không phải đơn giản, vậy trong bài viết này, tipjs sẽ cùng các bạn tìm hiểu về Map và Object là gì? Và khi nào nên sử dụng chúng? Và quan trọng hơn là performance giữa chúng như thế nào?


Map là gì?


Map là một data collection loại cấu trúc dữ liệu trừu tượng (abstract data structure), trong đó data được lưu trữ dưới dạng (key/value), chứa một key duy nhất và value được ánh xạ tới key đó. Và vì tính duy nhất của mỗi key được lưu trữ, và quan trọng là không trùng lặp trong việc lưu trữ. 


Đầu tiên bạn có thể đã bắt gặp câu hỏi này ở đâu đó - khi nào tôi nên sử dụng Map và khi nào tôi nên sử dụng Object? Mặc dù cả hai đều phù hợp cho các trường hợp sử dụng tương tự như nhau, nhưng có một số khác biệt nhất định giữa MapObject về cấu trúc dữ liệu, bạn hãy xem những sự khác biệt dưới đây, điều đó sẽ giúp cho bạn đưa ra một số quyết định rõ ràng hơn.

Tips: Chúng tôi đã xuất bản một bài viết về "Object Methods trong JavaScript mọi developers cần phải biết". Bạn có thể tìm hiểu về nhiều tính năng hơn của Object.


Key Field Map vs Object


Như đã nói ở trên cả hai MapObject đều có key-value, như sau:

// Map
{ 'a' => 1, 'b' => 2, 'c' => 3 }

// Object
{ 'a': 1, 'b': 2, 'c': 3 }

Nhưng đối với Object thì sẽ có một hạn chế đó là có những loại dữ liệu không thể sử dụng để làm key

  • Integer
  • String
  • Symbol

Trong khi đối với trường hợp sử dụng Map thì chúng ta có thể sử dụng bất kỳ loại dữ liệu nào để làm key

  • Bất kỳ kiểu dữ liệu primitive như ( Number, String...)
  • Object
  • Array
  • Function

Tóm lại, sự khác biệt đầu tiên đó là bạn có thể sủ dụng Map nếu bạn có nhiều data type phức tạp để làm key. Dưới đây là một ví dụ minh hoạ cho việc sử dụng cho giải thích trên Dưới đây minh họa việc sử dụng key cho một Object:

b = {
    [Symbol('symbol')]: 1,
    'string': 1,
    2: 1,
}

Object.keys(b).forEach(key => console.log(key))

// 2
// string
// undefined

Dưới đây minh họa việc sử dụng Map

a = new Map([
    [Symbol('symbol'), 1],
    ['string', 2],
    [2, 3]
])

a.forEach((_, key) => console.log(key))

// Symbol(symbol)
// string
// 2

Bạn thấy đấy, đó là sự khác biệt cho việc khi nào sử dụng Map và khi nào sử dụng Object. Hơn nữa đó là việc Map kế thừa từ Object cho nên, về mặt lập trình bạn có thể sử dụng prototype functions trên Map. Nhưng ngược lại, đối với một Object thì bạn không thể sử dụng bất kỳ chức năng nào của Map thì đơn giản là Map còn lớp con của Object.


Functions Map vs Object


Sự khác biệt tiếp theo đó là về chức năng giữa Map và Object. Điều này giúp bạn định hình rõ hơn về việc quyết định cái nào phù hợp với nhu cầu của bạn trong những tình huống khác. 

#Creating 

Để tạo một Object, chúng ta có nhiều cách để làm tốt hơn ví dụ như:


var object = {}
var object = new Object()
var object = Object.create(null)


Nhưng đối với Map, chỉ có một cách đó là sử dụng new Map()

var map = new Map()

# set và get Object

//set 
object['a'] = 1
object.a = 1

//get 

object.a
object['a']

# set và get Map

//set 
map.set('a', 1)

//get 
map.get('a')


#Kiểm tra 


nếu tồn tại Có các cách sau để kiểm tra xem key có tồn tại trong Object:

var exists = object.a !== undefined
var exists = 'a' in object

Trên Map, chúng tôi sử dụng chức năng has()

var exists = map.has('a')

#clear data 


Để xóa tất cả các properties trên một Object, chúng ta cần loop qua tất cả các properties và xoá từng thuộc tính một. Nhưng trên Map thì rất đơn giản đó là chúng ta có thể chỉ cần sử dụng clear()

map.clear()

# Get size data 


Để kiểm tra length một Object, bạn cần sử dụng Object.keys()

const size = Object.keys(object).length

Nhưng đối với Map, thì việc đó đơn giản hơn bao giờ hết chỉ sử dụng size()

const size = map.size

# Iteration 


Để Iteration qua một Object, chúng ta có thể sử dụng for... in.

// { 'a': 1, 'b': 2}
for (const key in object) {
 console.log(`${key}: ${object[key]}`)
 // a: 1
 // b: 2
}

Hoặc chúng ta cũng có thể lặp qua các key với Object.keys()

Object.keys(object).forEach(key => console.log(`${key}: ${object[key]}`))
// a: 1
// b: 2

Đối với một Map, nó rất khác nhau. Map là một iterable tích hợp, và vì vậy nó sẽ hoạt động với for... of.

// { 'a' => 1, 'b' => 2}
for (const pair of map) {
 console.log(pair)
}

// ["a", 1]
// ["b", 2]

Chúng tôi cũng có thể sử dụng Map's built-in đối với forEach()

map.forEach((value, key) => console.log(`${key}: ${value}`))

// a: 1
// b: 2

Khi nào sử dụng Map và khi nào sử dụng Object


Câu hỏi này chỉ trả lời cho tình huống cụ thể, chứ mỗi cá nhân hay mỗi mục đích lập trình là khác nhau, nhưng đây là suy nghĩ chung cho những gì mà chúng tôi đưa ra" 

Khi nào nên sử dụng Map: 

  • Nếu bạn cần một số loại dữ liệu phức tạp làm khóa, hãy sử dụng Map. Khá hữu ích cho các câu hỏi về thuật toán 
  • Nếu bạn cần thứ của key khi inserted, hãy sử dụng Map. Khi nghi ngờ về cấu trúc dữ liệu, thì chỉ cần sử dụng Map. Map linh hoạt hơn trong các trường hợp sử dụng và có cú pháp nhất quán. Bạn không thể đi sai với nó. 
  • Với tính năng như size(), clear() thì việc sử dụng như một array thì qua tốt cho những tình huống của bạn.


Khi nào nên sử dụng Object: 

  • Nếu bạn cần làm việc với JSON, hãy sử dụng Object. JSON sẽ không hoạt động với Map. Đây là một bài viết Stack Overflow về điều đó. 
  • Object là lựa chọn tuyệt vời cho các tình huống khi chúng ta chỉ cần cấu trúc đơn giản để lưu trữ dữ liệu và biết rằng tất cả các key là String hoặc Number (hoặc Symbol), bởi vì việc tạo Object đơn giản và truy cập thuộc tính của Object bằng một khóa cụ thể nhanh hơn nhiều so với việc tạo Map.


Map vs Object Performance

Để giúp bạn có một cách nhìn tốt hơn thì chúng tôi cung cấp cho bạn một tình huống test peformance giữa Map và Object.

var themap = new Map();
start = process.hrtime();
/***********************************/
for(let i = 0 ; i < N; i++ ) {
 let v = i%20;
 if (!themap.get(v))
 themap.set(v, i);
}
/***********************************/
console.log('section 1 : ' + timeUse(start));


obj = {};
start = process.hrtime();
/***********************************/
for(let i = 0 ; i < N; i++) {
 let v = i%20;
 if (!obj[v])
 obj[v] = 1;
}
/***********************************/
console.log('section 2 : ' + timeUse(start));

Kết quả test

# N = 1M
section 1 : 27290298ns
section 2 : 12362120ns

# N = 1K
section 1 : 1749059ns
section 2 : 63746ns

Ref:

Có thể bạn đã bị missing