Table of Contents
What is WeakMap
Syntax
Method
Why use WeakMap instead of Map
What is a weak reference
Why do weak references appear?
标记清除
引用计数
区别
WeakMap 应用
存储 DOM 节点
数据缓存
部署类中的私有属性
Home Web Front-end Vue.js What is WeakMap? Why is it used as a cache area in Vue3 responsive source code?

What is WeakMap? Why is it used as a cache area in Vue3 responsive source code?

Dec 22, 2021 am 10:19 AM
vue.js

This article will take you to understand WeakMap in Vue3 and introduce why WeakMap is used as the "cache area" in Vue 3 responsive source code. I hope it will be helpful to everyone.

What is WeakMap? Why is it used as a cache area in Vue3 responsive source code?

[Related recommendation: "vue.js Tutorial"]

Watch while reading some code of Vue 3 responsive principle When it is performing responsive processing, a "cache area" is created for each object using WeakMap. The code is as follows:

// 注意下面这句代码!
const reactiveMap = new WeakMap();

// 核心进行劫持的方法  处理 get 和 set 的逻辑
const mutableHandlers = {
    get,
    set
}

function reactive(target: object) {
    return createReactiveObject(target, mutableHandlers, reactiveMap);
}

/**
 * @description 创建响应式对象 
 * @param {Object} target 需要被代理的目标对象
 * @param {Function} baseHandlers 针对每种方式对应的不同处理函数
 * @param {Object} proxyMap WeakMap 对象
 */
function createReactiveObject(target, baseHandlers, proxyMap) {
    // 检测 target 是不是对象,不是对象直接返回,不进行代理
    if (!isObject(target)) {
        return target
    }
    const existsProxy = proxyMap.get(target);
    // 如果该对象已经被代理过了,则直接返回,不进行重复代理
    if (existsProxy) {
        return existsProxy
    }
    // 未被代理过,则创建代理对象
    const proxy = new Proxy(target,baseHandlers);
    // 缓存,避免重复代理,即避免 reactive(reactive(Object)) 的情况出现
    proxyMap.set(target,proxy); 
    return proxy
}
Copy after login

As can be seen from the above code, WeakMap The purpose of the cache area is to prevent objects from being repeatedly proxied.

Why does Vue 3 use WeakMap to cache proxy objects? Why not use other methods for caching, such as Map?

What is WeakMap

WeakMap The object is a collection of key-value pairs, where the keys are weak references. The keys must be objects, and the values ​​can be arbitrary.

Syntax

new WeakMap([iterable])
Copy after login

Iterable is an array (two-element array) or other iterable object whose elements are key-value pairs. Each key-value pair will be added to a new WeakMap.

Method

WeakMap There are four methods: get, set, has , delete, let’s take a look at its general usage:

const wm1 = new WeakMap(),
      wm2 = new WeakMap(),
      wm3 = new WeakMap();

const o1 = {},
      o2 = function() {},
      o3 = window;

wm1.set(o1, 37);
wm1.set(o2, "azerty");
wm2.set(o1, o2); // value 可以是任意值,包括一个对象或一个函数
wm2.set(o3, undefined);
wm2.set(wm1, wm2); // 键和值可以是任意对象,甚至另外一个 WeakMap 对象

wm1.get(o2); // "azerty"
wm2.get(o2); // undefined,wm2 中没有 o2 这个键
wm2.get(o3); // undefined,值就是 undefined

wm1.has(o2); // true
wm2.has(o2); // false
wm2.has(o3); // true (即使值是 undefined)

wm3.set(o1, 37);
wm3.get(o1); // 37

wm1.has(o1);   // true
wm1.delete(o1);
wm1.has(o1);   // false
Copy after login

Why use WeakMap instead of Map

In JavaScript, the map API can be implemented through four API methods sharing two arrays (one for keys and one for values). In this way, when setting a value to this map, the key and value will be added to the end of both arrays at the same time. This makes the key and value indexes correspond in the two arrays. When getting a value from this map, you need to iterate through all the keys and then use the index to retrieve the corresponding value from the array where the value is stored.

But such an implementation will have two big shortcomings. First, the assignment and search operations have a time complexity of O(n) (n is the key number of value pairs), because both operations require traversing the entire array to match.

Another disadvantage is that it may cause memory leak, because the array will always reference each key and value. Such references prevent the garbage collection algorithm from recycling them, even if no other references exist.

let jser = { name: "dachui" };

let array = [ jser ];

jser = null; // 覆盖引用
Copy after login

In the above code, we put an object into the array, then as long as the array exists, then the object will also exist, even if there are no other references to the object.

let jser = { name: "dachui" };

let map = new Map();
map.set(jser, "");

jser = null; // 覆盖引用
Copy after login

Similarly, if we use an object as a key for a regular Map, then the object will exist when the Map exists. It takes up memory and will not be reclaimed by the garbage collection mechanism.

In contrast, the native WeakMap holds a weak reference for each key object, which means that garbage collection can Do it correctly.

It is precisely because of such weak references that key of WeakMap is not enumerable (no method can give all key) . If key is enumerable, its list will be affected by the garbage collection mechanism, resulting in undefined results. Therefore, if you want a list of key values ​​for this type of object, you should use a Map.

To sum up, we can draw the following conclusion: The object pointed to by the key of WeakMap is not counted in the garbage collection mechanism.

So, if you want to add data to the object and don't want to interfere with the garbage collection mechanism, you can use WeakMap.

Everyone should know after seeing this, the reason why Vue 3 uses WeakMap as a buffer is to correctly garbage collect the data that is no longer used.

What is a weak reference

Regarding "weak reference", Wikipedia gives the answer:

In computer programming, Weak reference and Strong Reference Relative, refers to a reference that cannot ensure that the object it refers to will not be recycled by the garbage collector. An object is considered inaccessible (or weakly accessible) if it is only referenced by weak references, and therefore may be recycled at any time.

Why do weak references appear?

So, why do weak references appear? In addition to solving the above problems, what other problems can weak references solve? To answer these questions, we first need to understand how the V8 engine performs garbage collection.

For JSer, memory management is automatic and invisible, all thanks to the V8 engine silently helping us find the files we don’t need to use behind the scenes. memory and clean it up.

So, what happens when we no longer need something, V8 How does the engine find it and clean it up?

现在各大浏览器通常用采用的垃圾回收有两种方法,一种是「引用计数」,另外一种就是「标记清除」。下面我们来看一下:

标记清除

标记清除被称为 mark-and-sweep,它是基于 可达性 来判断对象是否存活的,它会定期执行以下「垃圾回收」步骤:

  • 垃圾收集器找到所有的根,并标记(记住)它们。

  • 然后它遍历并标记来自它们的所有引用。所有被遍历到的对象都会被记住,以免将来再次遍历到同一个对象。

  • ……如此操作,直到所有可达的(从根部)引用都被访问到。

  • 没有被标记的对象都会被删除。

我们还可以将这个过程想象成从根溢出一个巨大的油漆桶,它流经所有引用并标记所有可到达的对象,然后移除未标记的。

引用计数

引用计数方式最基本的形态就是让每个被管理的对象与一个引用计数器关联在一起,该计数器记录着该对象当前被引用的次数,每当创建一个新的引用指向该对象时其计数器就加 1,每当指向该对象的引用失效时计数器就减 1。当该计数器的值降到 0 就认为对象死亡。

区别

引用计数与基于「可达性」的标记清除的内存管理方式最大的区别就是,前者只需要 局部的信息,而后者需要 全局的信息

在引用计数中每个计数器只记录了其对应对象的局部信息 —— 被引用的次数,而没有(也不需要)一份全局的对象图的生死信息。

由于只维护局部信息,所以不需要扫描全局对象图就可以识别并释放死对象。但也因为缺乏全局对象图信息,所以 无法处理循环引用 的状况。

所以,更高级的引用计数实现会引入 弱引用 的概念来打破某些已知的循环引用。

WeakMap 应用

存储 DOM 节点

WeakMap 应用的典型场合就是以 DOM 节点作为键名。下面是一个例子。

const myWeakmap = newWeakMap();
myWeakmap.set(
  document.getElementById('logo'),
  { timesClicked: 0 },
);
document.getElementById('logo').addEventListener('click', () => {
  const logoData = myWeakmap.get(document.getElementById('logo'));
  logoData.timesClicked++;
}, false);
Copy after login

上面代码中,document.getElementById('logo') 是一个 DOM 节点,每当发生 click 事件,就更新一下状态。我们将这个状态作为值放在 WeakMap 里,对应的键就是这个节点对象。一旦这个 DOM 节点删除,该状态就会自动消失,不存在内存泄漏风险。

数据缓存

谜底就在谜面上,文章一开头我们提出的问题就是这里的答案。Vue 3 在实现响应式原理的时候就是使用了 WeakMap 来作为响应式对象的「缓存区」。

关于这一点用法也很简单,当我们需要关联对象和数据,比如在不修改原有对象的情况下储存某些属性或者根据对象储存一些计算的值等,而又不想手动去管理这些内存问题的时候就可以使用 WeakMap

部署类中的私有属性

WeakMap 的另一个用处是部署类中的私有属性。

值得一提的是,TypeScript 中已经实现的 private 私有属性原理就是利用 WeakMap

私有属性应该是不能被外界访问到,不能被多个实例共享,JavaScript 中约定俗成地使用下划线来标记私有属性和方法,一定程度来说是不靠谱的。

下面我们用三种方法来实现:

  • 版本一:闭包
const testFn = (function () {
  let data;

  class Test {
    constructor(val) {
      data = val
    }
    getData() {
      return data;
    }
  }
  return Test;
})();

let test1 = new testFn(3);
let test2 = new testFn(4);
console.log(test1.getData()); // 4
console.log(test2.getData()); // 4
Copy after login

可以看到最后都输出 4,多实例共享私有属性了,所以版本一不符合。

  • 版本二:Symbol
const testFn = (function () {
  let data = Symbol('data')

  class Test {
    constructor(val) {
      this[data] = val
    }
    getData() {
      return this[data]
    }
  }
  return Test;
})();

let test1 = new testFn(3);
let test2 = new testFn(4);
console.log(test1.getData()); // 3
console.log(test2.getData()); // 4

console.log(test1[Object.getOwnPropertySymbols(test1)[0]]); // 3
console.log(test2[Object.getOwnPropertySymbols(test2)[0]]); // 4
Copy after login

使用 Symbol 虽然实现了而且正确输出了 34,但是我们发现可以在外界不通过 getData 方法直接拿到私有属性,所以这种方法也不满足我们的要求。

  • 版本三:WeakMap
const testFn = (function () {
  let data = new WeakMap()

  class Test {
    constructor(val) {
      data.set(this, val)
    }
    getData() {
      return data.get(this)
    }
  }
  return Test;
})();

let test1 = new testFn(3);
let test2 = new testFn(4);
console.log(test1.getData()); // 3
console.log(test2.getData()); // 4
Copy after login

如上,完美解决~~

更多编程相关知识,请访问:编程入门!!

The above is the detailed content of What is WeakMap? Why is it used as a cache area in Vue3 responsive source code?. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Repo: How To Revive Teammates
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: How To Get Giant Seeds
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Use vue-cropper to crop images in the vue project Use vue-cropper to crop images in the vue project Oct 31, 2022 pm 07:16 PM

How to crop images in vue project? The following article will introduce to you how to use vue-cropper to crop images. I hope it will be helpful to you!

Let's talk in depth about reactive() in vue3 Let's talk in depth about reactive() in vue3 Jan 06, 2023 pm 09:21 PM

Foreword: In the development of vue3, reactive provides a method to implement responsive data. This is a frequently used API in daily development. In this article, the author will explore its internal operating mechanism.

Practical combat: Develop a plug-in in vscode that supports vue files to jump to definitions Practical combat: Develop a plug-in in vscode that supports vue files to jump to definitions Nov 16, 2022 pm 08:43 PM

vscode itself supports Vue file components to jump to definitions, but the support is very weak. Under the configuration of vue-cli, we can write many flexible usages, which can improve our production efficiency. But it is these flexible writing methods that prevent the functions provided by vscode itself from supporting jumping to file definitions. In order to be compatible with these flexible writing methods and improve work efficiency, I wrote a vscode plug-in that supports Vue files to jump to definitions.

Detailed graphic explanation of how to integrate the Ace code editor in a Vue project Detailed graphic explanation of how to integrate the Ace code editor in a Vue project Apr 24, 2023 am 10:52 AM

Ace is an embeddable code editor written in JavaScript. It matches the functionality and performance of native editors like Sublime, Vim, and TextMate. It can be easily embedded into any web page and JavaScript application. Ace is maintained as the main editor for the Cloud9 IDE and is the successor to the Mozilla Skywriter (Bespin) project.

Explore how to write unit tests in Vue3 Explore how to write unit tests in Vue3 Apr 25, 2023 pm 07:41 PM

Vue.js has become a very popular framework in front-end development today. As Vue.js continues to evolve, unit testing is becoming more and more important. Today we’ll explore how to write unit tests in Vue.js 3 and provide some best practices and common problems and solutions.

A brief analysis of how to handle exceptions in Vue3 dynamic components A brief analysis of how to handle exceptions in Vue3 dynamic components Dec 02, 2022 pm 09:11 PM

How to handle exceptions in Vue3 dynamic components? The following article will talk about Vue3 dynamic component exception handling methods. I hope it will be helpful to everyone!

What is the difference between componentization and modularization in vue What is the difference between componentization and modularization in vue Dec 15, 2022 pm 12:54 PM

The difference between componentization and modularization: Modularization is divided from the perspective of code logic; it facilitates code layered development and ensures that the functions of each functional module are consistent. Componentization is planning from the perspective of UI interface; componentization of the front end facilitates the reuse of UI components.

In-depth discussion of how vite parses .env files In-depth discussion of how vite parses .env files Jan 24, 2023 am 05:30 AM

When using the Vue framework to develop front-end projects, we will deploy multiple environments when deploying. Often the interface domain names called by development, testing and online environments are different. How can we make the distinction? That is using environment variables and patterns.

See all articles