📜 ⬆️ ⬇️

The Subtleties of ES6: Collections (Part 2)

From the translator: this is the second part of the translation of the article about the collection in EcmaScript 6. The first part can be read here . For various reasons, the translation of the second part was delayed for quite a long time.

Map


Map (associative array) is a collection of key-value pairs. This is what the Map can do:


What is there to complain about? Here are some features that are not in the ES6 collections, and which, I think, would be useful:
')


Again, these features are easy to add.

OK. Remember how I started this article by thinking about how the care of JS execution in a browser affects the design of a language and its features? Now we will start talking about it. I have three examples. Here are the first two.

JS differences, part 1: hash tables without hash codes?


There is one useful feature that, as far as I know, collection classes in ES6 do not support at all.

Suppose we have a Set of URL objects.
 var urls = new Set; urls.add(new URL(location.href)); //  URL- urls.add(new URL(location.href)); //   ? alert(urls.size); // 2 

These two URLs must be interpreted as identical. All fields have the same. But in Javascript these are two different objects, and it’s impossible to overload the notion of language about the equality of objects.

Other languages ​​support this. In Java, Python, Ruby, individual classes can overload equality. In many Scheme implementations, individual hash tables can be created using different concepts of equality. C ++ supports both options.

However, all these mechanisms require users to implement custom hash functions, and all of them expose the system hash function by default. The committee decided not to put on hash codes in Javascript - at least for now - because of open questions about interoperability and security, which is not a reason for such concern in other languages.

JS Differences, Part 2: Surprise! Predictable!


You probably think that deterministic behavior on the part of the computer is not a reason for surprise. But people are often surprised when I tell them that the iteration over the elements in Map and Set occurs in the order they are added to the collection. She is determined.

We are used to the arbitrariness of certain aspects of hash tables. We learned to accept it. But there are damn good reasons to try to avoid accidents. As I wrote in 2012:

When it was discussed in February 2012, I was in an arbitrary order of iteration . I conducted an experiment to prove that tracking the order of insertion would make the hash tables too slow. I wrote a couple of benchmarks in C ++. The result struck me.

This is how we ended up with hash tables that monitor the order of insertion in JS!

Good reasons to use weak collections


In early June 2015, we discussed an example that includes an animation library on JS. We wanted to store a boolean flag for each DOM object, like this:
 if (element.isMoving) { smoothAnimations(element); } element.isMoving = true; 

Unfortunately, setting expandable properties in a DOM object in this way is a bad idea, as discussed in the article. In that article, we solved the problem using symbols. But can we do the same using Set ? It might look like this:
 if (movingSet.has(element)) { smoothAnimations(element); } movingSet.add(element); 

There is only one drawback: Map and Set have a strong reference to each key and each value. This means that if the DOM element has been removed from the document, the garbage collector cannot free memory until the element is removed from the movingSet . Libraries usually cope with clearing the memory after themselves. This can lead to memory leaks.

ES6 offers an amazing solution for this. Make movingSet WeakSet instead of Set . The leak problem is solved!

So, you can solve this problem with weak collections or symbols. What's better? The discussion about the advantages and disadvantages of each method will make this post too long. If you can use one character throughout the life of a web page, then this is probably normal. If you want to use a lot of short-lived characters, this is an alarming sign: consider using WeakSet instead to prevent memory leaks.

WeakMap and WeakSet


WeakMap and WeakSet specified to behave in the same way as Map and Set , but with the following restrictions:

Notice that none of the weak collections are iterable. You can not get records from the collection except by the corresponding key.

These restrictions allow the garbage collector to collect dead objects from living weak collections. A similar effect can be achieved with weak references or weak-keyed dictionaries , but weak collections in ES6 have all the advantages of memory management without disclosing the fact that garbage collection has occurred in the scripts.

JS differences, part 3: hiding undetected garbage collector


Under the hood, weak collections are implemented as ephemeron tables .

In short, WeakSet does not keep strong references to objects within itself. When an object in WeakSet is collected by the garbage collector, it is simply deleted from WeakSet . Same for WeakMap . It does not have strong references to any key. If the key is alive, alive and meaningful.

Why all these restrictions? Why not just add weak links in JS?

Again, the committee does not want to disclose non-deterministic behavior to scripts. Weak cross-browser compatibility - the curse of web development. Weak references reveal the details of the implementation of the garbage collector - the very definition of platform-specific arbitrary behavior. Of course, applications should not depend on the details of a specific platform, but weak links make it difficult to understand how you depend on the behavior of the garbage collector in the current browser in which you run your application. It's hard to deal with them.

In contrast, weak collections in ES6 have a more limited, but strong set of features. The fact that a key or a value has been assembled by the garbage collector is not observed, so that applications can in no way depend on it, even by accident.

This is a specific case of how web-specific problems led to an amazing design solution that improved JS as a language.

Where can I use collections?


All four collection classes are supported in Firefox, Chrome, MS Edge and Safari. To support older browsers, use a polyfill type es6-collections .

WeakMap was first implemented in Firefox by Andreas Galom, a former Mozilla CTO. Tom Schuster implemented WeakSet . I implemented Map and Set . Thanks to Tooru Fujisawa for the patches.

Next week, the “Subtleties of ES6” take a two-week break. This series of articles has told a lot, but some of the most powerful features of ES6 will be described. Join us when we come back with new content on July 9th.

Source: https://habr.com/ru/post/261417/


All Articles