In-depth Understanding of ES6 007 [Study Notes]

Set and Map Collections. In JS, there is an `in` operator that can determine if a property exists in an object without needing to read the object's value, returning true if it exists. However, the `in` operator also checks the object's prototype chain, so using this method is only relatively safe when the object's prototype is null. Set Collection: `let set = new Set()` `set.add(5)` `set.add("5")` `console.log(s…`

Set Collection and Map Collection

In JS, there is an in operator, which can determine if a property exists in an object without needing to read the object's value; if it exists, it returns true. However, the `in` operator also checks the object's prototype, so this method is only reliable when the object's prototype is null.

Set Collection

let set = new Set()
set.add(5)
set.add("5")
console.log(set.size) // 2
const key1={},key2={}
set.add(key1)
set.add(key1)
console.log(set.size) // 4
// 传入相同值实际上会被忽略
let set1 = new Set(1,2,3,4,5,5,5,5)
console.log(set.size) //5
set1.has(5) //true
set1.has(6) // false
set1.delete(5)
set1.has(5) //false

set1.clear() // 所有元素被清除

A Set collection does not perform forced type conversion on stored values; the number 5 and the string "5" can exist as two independent elements (the engine uses `Object.is()` as mentioned before for judgment). If multiple objects are added to a Set, they remain independent of each other.

Set Collection's forEach Method

The callback function of the forEach() method accepts the following 3 parameters

  • The next index position in the Set collection
  • A value identical to the first parameter
  • The Set collection being iterated over itself

The `forEach()` method of a Set collection has a peculiar difference from the `forEach()` method in arrays: the values of the first two parameters of the callback function are actually the same. In fact, the `forEach()` callback function of a Map collection also accepts 3 parameters, where the first two are the value and the key, respectively.

The second parameter of the `forEach` function is the same as for arrays; if `this` needs to be used within the callback function, it can be passed as the second argument.

let set = new Set([1,2])
let processor = {
  output(value){
    console.log(value)
  },
  process(dataSet){
    // 这里使用箭头函数,就无须再将this作为第二个参数传入回调函数了
    dataSet.forEach(function(value){
      this.output(value)
    },this)
  }
}
processor.process(set)

Although Set collections are more suitable for tracking multiple values and each element in the collection can be manipulated using the `forEach()` method, you cannot access elements in a collection directly by index like you would with array elements. If necessary, it's best to convert the Set collection into an array first.

let set = new Set([1,2,3,3,3,4,5])
arrray = [...set]
console.log(array) // [1,2,3,4,5] 去重

function eliminateDuplicates(items){
  return [...new Set(items)]
}
let numbers = [1,2,3,3,3,4,5],
noDuplicates = eliminateDuplicates(numbers);
console.log(noDuplicates); // [1,2,3,4,5]

Weak Set Collection

Storing an object in a Set instance is similar to storing it in a variable: as long as a reference exists in the Set instance, the garbage collector cannot free the object's memory space. Thus, the Set type mentioned earlier can be considered a Set collection with strong references. As follows:

let set = new Set(),
key = {};
set.add(key);
console.log(set.size) // 1
// 移除原始引用
key = null;
console.log(set.size) // 1
// 重新取回原始引用
key = [...set][0]

For example, if we use this Set to store a DOM object, and a script removes this DOM element, the Set will still retain this reference (causing a memory leak). Therefore, ES6 introduced the WeakSet collection. A WeakSet can only store weak references to objects and cannot store primitive values; if a weak reference in the collection is the object's only reference, it will be garbage collected and its memory released.

// 集合支持add()/has()/delete()
let set = new WeakSet(),key = {};
// 向集合添加对象
set.add(key);
console.log(set.has(key)); // true
set.delete(key);
console.log(set.has(key)); // false
let key1 = {}, key2 = {};
set = new WeakSet([key1,key2]) // 如果数组中包含其非对象值,程序会抛出错误
console.log(set.has(key1)) // true
console.log(set.has(key2)) // true

// #################
// 移除对象key的最后一个强引用(Weak Set中的引用也自动移除)
let set = new Set(),
key = {};
set.add(key);
console.log(set.has(key)) // true
// 移除对象key的最后个强引用(Weak Set中的引用也自动移除)
key = null;
// 这段代码执行过后,就无法访问WeakSet中的key的引用了,由于我们需要向has方法传递一个强引用才能验证这个弱引用是否已被移除了。
  • WeakSet
  • Passing non-object arguments to the add/has/delete methods will cause the program to throw an error.
  • Not iterable; cannot use `for-of` loops.
  • Does not expose any iterators (`keys` and `values`), so its contents cannot be inspected by the program itself.
  • Does not support `forEach`.
  • Does not support `size`.

Map

  • set
  • get
  • has
  • delete
  • clear
  • size property

Initialization Method

let map = new Map([["name","Nicholas"],["age",23]])

forEach((value,key,ownerMap)=>{}, binding context)

let map = new Map([["name","Nicholas"],["age",23]])
map.forEach(function(value,key,ownerMap){
   console.log(key+" "+value);
   console.log(ownerMap === map)
})

WeakMap

The principle is consistent with WeakSet: keys are weak references to objects, and keys can only store objects.

let map = new WeakMap(),
element = document.querySelector('.element');
map.set(element,"Original")
let value = map.get(element)
console.log(value) // Original
// 移除element元素
element.parentNode.removeChild(element);
element = null;
// 此时Weak Map集合为空

Private Object Data

function Person(name){
  this._name = name;
}
Person.prototype.getName = function(){
  return this._name;
}
// 约定前缀为下划线的属性为私有属性,不允许在对象实例外改变这个属性。例如,只能通过getName()方法读取this._name,所以它也有可能在无意间被覆写

ES5 can create an object with nearly true private data using the following pattern:

var Person = (function(){
  var privateData = {},
  privateId = 0;
  function Person(name){
    Object.defineProperty(this,"_id",{value:privateId++})
    privateData[this._id] = {
      name:name
    }
  }
  Person.prototype.getName = function(){
    return privateData[this._id].name
  }
  return Person
}())

When the `Person` constructor is called, the value of the `_id` property is incremented by 1. This property is non-enumerable, non-configurable, and non-writable. The biggest problem with the above code is the inability to actively manage it; since it's impossible to know when an object instance is destroyed, the data in `privateData` will never disappear. However, using a WeakMap collection can solve this problem.

let Person = (function(){
  let privateData = new WeakMap();
  function Person(name){
    privateData.set(this,{name:name})
  }
  Person.prototype.getName = function(){
    return privateData.get(this).name
  }
  return Person
}())
// 只要对象实例被销毁,相关信息也会被销毁,从而保证了信息的私有性

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/4333

(0)
Walker的头像Walker
上一篇 Mar 8, 2025 12:51
下一篇 Mar 8, 2025 12:51

Related Posts

  • In-depth Understanding of ES6 011 [Learning Notes]

    Promises and Asynchronous Programming

    Because the execution engine is single-threaded, it needs to track the code that is about to run. This code is placed in a task queue. Whenever a piece of code is ready to execute, it is added to the task queue, and whenever a piece of code in the engine finishes execution, the event loop executes the next task in the queue. A Promise acts as a placeholder for the result of an asynchronous operation. It doesn't subscribe to an event or pass a callback function to the target function. Instead, it allows the function to return a Promise, like this...

    Personal Mar 8, 2025
    1.1K00
  • In-depth Understanding of ES6 005 [Study Notes]

    Destructuring: Making data access more convenient. If you declare variables using `var`, `let`, or `const` with destructuring, you must provide an initializer (i.e., the value on the right side of the equals sign). The following will cause an error:
    // Syntax error `var {tyep,name}`
    // Syntax error `let {type,name}`
    // Syntax error `const {type,name}`
    To assign values to already declared variables using destructuring, consider the following:
    `let node = { type:&qu...`

    Personal Mar 8, 2025
    1.2K00
  • TS Everest 004 [Study Notes]

    Type manipulation type-1 // Built-in // Partial, Required, Readonly for modifying types // Pick, Omit for manipulating data structures // Exclude, Extract for manipulating union types // Parameters, ReturnType, infer // String types, template literal types `${}` + infer, PartialPropsOptional ...

    Personal Mar 27, 2025
    1.4K00
  • Go Engineer System Course 013 [Study Notes]

    Order transactions, whether deducting inventory first or later, will both affect inventory and orders. Therefore, distributed transactions must be used to address business issues (e.g., unpaid orders). One approach is to deduct inventory only after successful payment (e.g., an order was placed, but there was no inventory at the time of payment). Another common method is to deduct inventory when the order is placed, but if payment isn't made, the order is returned/released upon timeout.

    Transactions and Distributed Transactions
    1. What is a transaction?
    A transaction is an important concept in database management systems. It is a collection of database operations, which either all execute successfully, or all...

    Personal Nov 25, 2025
    22400
  • Go Engineering Systematic Course 003 [Study Notes]

    grpc grpc grpc-go grpc seamlessly integrates protobuf protobuf. For those of you accustomed to using JSON and XML data storage formats, I believe most have never heard of Protocol Buffer. Protocol Buffer is actually a lightweight & efficient structured data storage format developed by Google, and its performance is truly much, much stronger than JSON and XML! protobuf…

    Personal Nov 25, 2025
    18600
EN
简体中文 繁體中文 English
欢迎🌹 Coding never stops, keep learning! 💡💻 光临🌹