Apa kegunaan sebenarnya dari ES6 WeakMap?

397

Apa kegunaan sebenarnya dari WeakMapstruktur data yang diperkenalkan dalam ECMAScript 6?

Karena kunci dari peta yang lemah menciptakan referensi yang kuat untuk nilai yang sesuai, memastikan bahwa nilai yang telah dimasukkan ke dalam peta yang lemah tidak akan pernah hilang selama kuncinya masih hidup, itu tidak dapat digunakan untuk tabel memo, cache atau apa pun yang biasanya Anda gunakan menggunakan referensi lemah, peta dengan nilai lemah, dll.

Tampaknya bagi saya bahwa ini:

weakmap.set(key, value);

... hanyalah cara bundaran untuk mengatakan ini:

key.value = value;

Kasus penggunaan konkret apa yang saya lewatkan?

Valderman
sumber
10
Posting blog.
Runcing
2
Dan satu lagi - ilikekillnerds.com/2015/02/what-are-weakmaps-in-es6
James Sumners
35
Kasus penggunaan dunia nyata: Menyimpan data khusus untuk node DOM.
Felix Kling
Semua kasus penggunaan yang Anda sebutkan untuk referensi yang lemah juga sangat penting. Mereka jauh lebih sulit untuk ditambahkan ke bahasa karena mereka memperkenalkan nondeterminisme. Mark Miller dan yang lainnya telah melakukan banyak pekerjaan pada referensi yang lemah dan saya pikir mereka akhirnya datang. Akhirnya
Benjamin Gruenbaum
2
WeakMaps dapat digunakan untuk mendeteksi kebocoran memori: stevehanov.ca/blog/?id=148
theWebalyst

Jawaban:

513

Secara fundamental

WeakMaps menyediakan cara untuk memperluas objek dari luar tanpa mengganggu pengumpulan sampah. Kapan pun Anda ingin memperluas objek tetapi tidak bisa karena disegel - atau dari sumber eksternal - WeakMap dapat diterapkan.

WeakMap adalah peta (kamus) tempat kunci lemah - yaitu, jika semua referensi ke kunci hilang dan tidak ada lagi referensi ke nilai - nilainya dapat berupa sampah yang dikumpulkan. Mari kita tunjukkan ini pertama melalui contoh, kemudian jelaskan sedikit dan akhirnya selesai dengan penggunaan nyata.

Katakanlah saya menggunakan API yang memberi saya objek tertentu:

var obj = getObjectFromLibrary();

Sekarang, saya punya metode yang menggunakan objek:

function useObj(obj){
   doSomethingWith(obj);
}

Saya ingin melacak berapa kali metode dipanggil dengan objek tertentu dan melaporkan jika itu terjadi lebih dari N kali. Secara naif orang akan berpikir untuk menggunakan Peta:

var map = new Map(); // maps can have object keys
function useObj(obj){
    doSomethingWith(obj);
    var called = map.get(obj) || 0;
    called++; // called one more time
    if(called > 10) report(); // Report called more than 10 times
    map.set(obj, called);
}

Ini berfungsi, tetapi memiliki kebocoran memori - kami sekarang melacak setiap objek perpustakaan yang diteruskan ke fungsi yang membuat objek perpustakaan tidak pernah menjadi sampah yang dikumpulkan. Sebaliknya - kita bisa menggunakan aWeakMap :

var map = new WeakMap(); // create a weak map
function useObj(obj){
    doSomethingWith(obj);
    var called = map.get(obj) || 0;
    called++; // called one more time
    if(called > 10) report(); // Report called more than 10 times
    map.set(obj, called);
}

Dan kebocoran memori hilang.

Gunakan kasing

Beberapa case yang dapat menyebabkan kebocoran memori dan diaktifkan oleh WeakMaps termasuk:

  • Menyimpan data pribadi tentang objek tertentu dan hanya memberikan akses kepada orang-orang dengan referensi ke Peta. Pendekatan yang lebih ad-hoc akan datang dengan proposal simbol pribadi tapi itu sudah lama dari sekarang.
  • Menyimpan data tentang objek perpustakaan tanpa mengubahnya atau mengeluarkan biaya tambahan.
  • Menyimpan data tentang satu set kecil objek di mana banyak objek dari tipe ada untuk tidak menimbulkan masalah dengan kelas tersembunyi yang digunakan mesin JS untuk objek dari tipe yang sama.
  • Menyimpan data tentang objek host seperti simpul DOM di browser.
  • Menambahkan kemampuan ke objek dari luar (seperti contoh acara emitor di jawaban lainnya).

Mari kita lihat penggunaan yang sebenarnya

Dapat digunakan untuk memperluas objek dari luar. Mari kita berikan contoh praktis (diadaptasi, semacam nyata - untuk menegaskan) dari dunia nyata Node.js.

Katakanlah Anda Node.js dan Anda memiliki Promiseobjek - sekarang Anda ingin melacak semua janji yang saat ini ditolak - namun, Anda tidak ingin mencegahnya dari sampah yang dikumpulkan seandainya tidak ada referensi.

Sekarang, Anda tidak ingin menambahkan properti ke objek asli karena alasan yang jelas - jadi Anda terjebak. Jika Anda menyimpan referensi untuk janji-janji Anda menyebabkan kebocoran memori karena tidak ada pengumpulan sampah dapat terjadi. Jika Anda tidak menyimpan referensi maka Anda tidak dapat menyimpan informasi tambahan tentang janji individu. Skema apa pun yang melibatkan penyimpanan ID janji secara inheren berarti Anda memerlukan referensi untuk itu.

Masukkan WeakMaps

WeakMaps berarti bahwa kunci lemah. Tidak ada cara untuk menyebutkan peta yang lemah atau untuk mendapatkan semua nilainya. Di peta yang lemah, Anda bisa menyimpan data berdasarkan kunci dan ketika kunci mendapat sampah dikumpulkan begitu juga nilainya.

Ini berarti bahwa dengan janji Anda dapat menyimpan status tentangnya - dan objek itu masih dapat dikumpulkan sebagai sampah. Kemudian, jika Anda mendapatkan referensi ke suatu objek, Anda dapat memeriksa apakah Anda memiliki keadaan terkait dan melaporkannya.

Ini digunakan untuk menerapkan kait penolakan yang tidak ditangani oleh Petka Antonov karena ini :

process.on('unhandledRejection', function(reason, p) {
    console.log("Unhandled Rejection at: Promise ", p, " reason: ", reason);
    // application specific logging, throwing an error, or other logic here
});

Kami menyimpan informasi tentang janji di peta dan dapat mengetahui kapan janji yang ditolak ditangani.

Benjamin Gruenbaum
sumber
8
Halo! Bisakah Anda memberi tahu saya bagian mana dari kode contoh yang menyebabkan kebocoran memori?
ltamajs
15
@ ltamajs4 yakin, dalam useObjcontoh menggunakan a Mapdan bukan a WeakMapkita menggunakan objek yang diteruskan sebagai kunci peta. Objek tidak pernah dihapus dari peta (karena kita tidak akan tahu kapan harus melakukannya) sehingga selalu ada referensi untuk itu dan itu tidak pernah bisa menjadi sampah yang dikumpulkan. Dalam contoh WeakMap segera setelah semua referensi lain ke objek hilang - objek dapat dihapus dari WeakMap. Jika Anda masih tidak yakin dengan apa yang saya maksud, beri tahu saya
Benjamin Gruenbaum
@Benjamin, Kita perlu membedakan antara kebutuhan untuk cache yang peka terhadap memori dan kebutuhan untuk data_object tuple. Jangan mengacaukan kedua persyaratan terpisah ini. calledContoh Anda lebih baik ditulis menggunakan jsfiddle.net/f2efbm7z dan tidak menunjukkan penggunaan peta yang lemah. Bahkan, bisa ditulis lebih baik dalam total 6 cara, yang saya akan daftar di bawah ini.
Pacerier
Pada dasarnya, tujuan peta yang lemah adalah cache yang peka terhadap memori. Meskipun dapat digunakan untuk memperluas objek dari luar, itu adalah peretasan buruk yang tidak perlu dan jelas bukan tujuan yang tepat .
Pacerier
1
Jika Anda ingin menjaga hubungan antara janji dan berapa kali itu telah ditangani / ditolak, gunakan 1) simbol; p[key_symbol] = data. atau 2) penamaan unik; p.__key = data. atau 3) ruang lingkup pribadi; (()=>{let data; p.Key = _=>data=_;})(). atau 4) proksi dengan 1 atau 2 atau 3. atau 5) ganti / tambah kelas Janji dengan 1 atau 2 atau 3. atau 6) ganti / perpanjang kelas Janji dengan tupel anggota yang diperlukan. - Bagaimanapun, lemah peta tidak diperlukan kecuali Anda membutuhkan cache sensitif memori.
Pacerier
48

Jawaban ini tampaknya bias dan tidak dapat digunakan dalam skenario dunia nyata. Harap baca apa adanya, dan jangan menganggapnya sebagai opsi aktual untuk hal lain selain eksperimen

Sebuah use case bisa digunakan sebagai kamus untuk pendengar, saya punya rekan kerja yang melakukan itu. Ini sangat membantu karena setiap pendengar secara langsung ditargetkan dengan cara melakukan sesuatu. Selamat tinggallistener.on .

Tapi dari sudut pandang yang lebih abstrak, WeakMapsangat kuat untuk menurunkan material akses pada dasarnya apa pun, Anda tidak perlu ruang nama untuk mengisolasi anggotanya karena sudah tersirat oleh sifat struktur ini. Saya cukup yakin Anda bisa melakukan beberapa perbaikan memori besar dengan mengganti kunci objek yang canggung berlebihan (meskipun mendekonstruksi melakukan pekerjaan untuk Anda).


Sebelum membaca apa selanjutnya

Saya sekarang menyadari bahwa penekanan saya bukanlah cara terbaik untuk mengatasi masalah dan seperti yang ditunjukkan Benjamin Gruenbaum (lihat jawabannya, jika belum di atas saya: p), masalah ini tidak dapat diselesaikan dengan cara biasa Map, karena itu akan bocor, jadi kekuatan utama WeakMapadalah bahwa itu tidak mengganggu pengumpulan sampah mengingat bahwa mereka tidak menyimpan referensi.


Berikut adalah kode aktual rekan kerja saya (terima kasih kepada dia untuk berbagi)

Sumber lengkap di sini , ini tentang manajemen pendengar yang saya bicarakan di atas (Anda juga dapat melihat spesifikasi )

var listenableMap = new WeakMap();


export function getListenable (object) {
    if (!listenableMap.has(object)) {
        listenableMap.set(object, {});
    }

    return listenableMap.get(object);
}


export function getListeners (object, identifier) {
    var listenable = getListenable(object);
    listenable[identifier] = listenable[identifier] || [];

    return listenable[identifier];
}


export function on (object, identifier, listener) {
    var listeners = getListeners(object, identifier);

    listeners.push(listener);
}


export function removeListener (object, identifier, listener) {
    var listeners = getListeners(object, identifier);

    var index = listeners.indexOf(listener);
    if(index !== -1) {
        listeners.splice(index, 1);
    }
}


export function emit (object, identifier, ...args) {
    var listeners = getListeners(object, identifier);

    for (var listener of listeners) {
        listener.apply(object, args);
    }
}
kapak
sumber
2
Saya tidak mengerti bagaimana Anda akan menggunakan ini. Itu akan menyebabkan yang bisa diamati runtuh bersama dengan peristiwa terikat padanya ketika tidak lagi dirujuk. Masalah yang cenderung saya miliki adalah ketika Pengamat tidak lagi dirujuk. Saya pikir solusinya di sini hanya menyelesaikan setengah dari masalah. Saya tidak berpikir Anda dapat memecahkan masalah pengamat dengan WeakMap karena tidak dapat diperbaiki.
jgmjgm
1
Pendengar peristiwa buffering ganda mungkin cepat dalam bahasa lain, tetapi dalam kasus ini hanya esoteris dan lambat. Itu tiga sen ku.
Jack Giffin
@axelduch, Wow mitos pendengar-pegangan ini telah dijajakan sepanjang jalan ke komunitas Javascript, mendapatkan 40 upvotes! Untuk memahami mengapa jawaban ini sepenuhnya salah , lihat komentar di bawah stackoverflow.com/a/156618/632951
Pacerier
1
@Pacerier memperbarui jawabannya, terima kasih atas umpan baliknya
axelduch
1
@ Maxelduch, Ya, ada referensi dari sana juga.
Pacerier
18

WeakMap berfungsi dengan baik untuk enkapsulasi dan penyembunyian informasi

WeakMaphanya tersedia untuk ES6 ke atas. A WeakMapadalah kumpulan pasangan kunci dan nilai di mana kunci harus menjadi objek. Dalam contoh berikut, kami membuat a WeakMapdengan dua item:

var map = new WeakMap();
var pavloHero = {first: "Pavlo", last: "Hero"};
var gabrielFranco = {first: "Gabriel", last: "Franco"};
map.set(pavloHero, "This is Hero");
map.set(gabrielFranco, "This is Franco");
console.log(map.get(pavloHero));//This is Hero

Kami menggunakan set()metode untuk mendefinisikan hubungan antara suatu objek dan item lain (string dalam kasus kami). Kami menggunakan get()metode untuk mengambil item yang terkait dengan objek. Aspek yang menarik dari WeakMaps adalah fakta bahwa ia memegang referensi yang lemah ke kunci di dalam peta. Referensi yang lemah berarti bahwa jika objek dihancurkan, pengumpul sampah akan menghapus seluruh entri dari WeakMap, sehingga membebaskan memori.

var TheatreSeats = (function() {
  var priv = new WeakMap();
  var _ = function(instance) {
    return priv.get(instance);
  };

  return (function() {
      function TheatreSeatsConstructor() {
        var privateMembers = {
          seats: []
        };
        priv.set(this, privateMembers);
        this.maxSize = 10;
      }
      TheatreSeatsConstructor.prototype.placePerson = function(person) {
        _(this).seats.push(person);
      };
      TheatreSeatsConstructor.prototype.countOccupiedSeats = function() {
        return _(this).seats.length;
      };
      TheatreSeatsConstructor.prototype.isSoldOut = function() {
        return _(this).seats.length >= this.maxSize;
      };
      TheatreSeatsConstructor.prototype.countFreeSeats = function() {
        return this.maxSize - _(this).seats.length;
      };
      return TheatreSeatsConstructor;
    }());
})()
Michael Horojanski
sumber
4
Re "lemah peta berfungsi dengan baik untuk enkapsulasi dan penyembunyian informasi". Hanya karena Anda bisa, bukan berarti Anda harus melakukannya. Javascript memiliki cara standar untuk melakukan enkapsulasi dan penyembunyian informasi bahkan sebelum pelemahan peta ditemukan. Seperti pada saat ini, ada 6 cara untuk melakukannya . Menggunakan lemah peta untuk melakukan enkapsulasi adalah wajah buruk rupa.
Pacerier
12

๐— ๐—ฒ๐˜๐—ฎ๐—ฑ๐—ฎ๐˜๐—ฎ

Lemah Maps dapat digunakan untuk menyimpan metadata tentang elemen DOM tanpa mengganggu pengumpulan sampah atau membuat rekan kerja marah pada kode Anda. Misalnya, Anda bisa menggunakannya untuk mengindeks semua elemen dalam halaman web secara numerik.

๐—ช๐—ถ๐˜๐—ต๐—ผ๐˜‚๐˜ ๐—ช๐—ฒ๐—ฎ๐—ธ๐— ๐—ฎ๐—ฝ๐˜€ ๐—ผ๐—ฟ ๐—ช๐—ฒ๐—ฎ๐—ธ๐—ฆ๐—ฒ๐˜๐˜€:

var elements = document.getElementsByTagName('*'),
  i = -1, len = elements.length;

while (++i !== len) {
  // Production code written this poorly makes me want to cry:
  elements[i].lookupindex = i;
  elements[i].elementref = [];
  elements[i].elementref.push( elements[(i * i) % len] );
}

// Then, you can access the lookupindex's
// For those of you new to javascirpt, I hope the comments below help explain 
// how the ternary operator (?:) works like an inline if-statement
document.write(document.body.lookupindex + '<br />' + (
    (document.body.elementref.indexOf(document.currentScript) !== -1)
    ? // if(document.body.elementref.indexOf(document.currentScript) !== -1){
    "true"
    : // } else {
    "false"
  )   // }
);

๐—จ๐˜€๐—ถ๐—ป๐—ด ๐—ช๐—ฒ๐—ฎ๐—ธ๐— ๐—ฎ๐—ฝ๐˜€ ๐—ฎ๐—ป๐—ฑ ๐—ช๐—ฒ๐—ฎ๐—ธ๐—ฆ๐—ฒ๐˜๐˜€:

var DOMref = new WeakMap(),
  __DOMref_value = Array,
  __DOMref_lookupindex = 0,
  __DOMref_otherelement = 1,
  elements = document.getElementsByTagName('*'),
  i = -1, len = elements.length, cur;

while (++i !== len) {
  // Production code written this greatly makes me want to ๐Ÿ˜Š:
  cur = DOMref.get(elements[i]);
  if (cur === undefined)
    DOMref.set(elements[i], cur = new __DOMref_value)

  cur[__DOMref_lookupindex] = i;
  cur[__DOMref_otherelement] = new WeakSet();
  cur[__DOMref_otherelement].add( elements[(i * i) % len] );
}

// Then, you can access the lookupindex's
cur = DOMref.get(document.body)
document.write(cur[__DOMref_lookupindex] + '<br />' + (
    cur[__DOMref_otherelement].has(document.currentScript)
    ? // if(cur[__DOMref_otherelement].has(document.currentScript)){
    "true"
    : // } else {
    "false"
  )   // }
);

๐—ง๐—ต๐—ฒ ๐——๐—ถ๐—ณ๐—ณ๐—ฒ๐—ฟ๐—ฒ๐—ป๐—ฐ๐—ฒ

Perbedaannya mungkin terlihat dapat diabaikan, selain dari fakta bahwa versi peta lemah lebih panjang, namun ada perbedaan besar antara dua bagian kode yang ditunjukkan di atas. Dalam cuplikan kode pertama, tanpa peta yang lemah, potongan kode menyimpan referensi di antara elemen DOM. Ini mencegah elemen DOM dari pengumpulan sampah.(i * i) % lenmungkin tampak seperti bola aneh yang tidak akan digunakan siapa pun, tetapi pikirkan lagi: banyak kode produksi memiliki referensi DOM yang terpental di seluruh dokumen. Sekarang, untuk potongan kode kedua, karena semua referensi ke elemen lemah, ketika Anda menghapus node, browser dapat menentukan bahwa node tidak digunakan (tidak dapat dijangkau oleh kode Anda), dan dengan demikian hapus dari memori. Alasan mengapa Anda harus khawatir tentang penggunaan memori, dan jangkar memori (hal-hal seperti potongan kode pertama di mana elemen yang tidak digunakan disimpan dalam memori) adalah karena lebih banyak penggunaan memori berarti lebih banyak upaya browser GC (untuk mencoba membebaskan memori ke avert a browser crash) berarti pengalaman menjelajah lebih lambat dan terkadang browser mengalami crash.

Adapun polyfill untuk ini, saya akan merekomendasikan perpustakaan saya sendiri ( ditemukan di sini @ github ). Ini adalah pustaka yang sangat ringan yang hanya akan mengisinya tanpa kerangka kerja yang terlalu rumit yang mungkin Anda temukan di polyfill lainnya.

~ Selamat coding!

Jack Giffin
sumber
1
Terima kasih atas penjelasan yang jelas. Contoh bernilai lebih dari kata apa pun.
newguy
@lzzery, Re " Ini mencegah elemen DOM dari pengumpulan sampah ", semua yang Anda butuhkan adalah mengatur elementske nol dan Anda selesai: Ini akan menjadi GCed. & Re " Referensi DOM yang terpental di seluruh dokumen ", tidak masalah sama sekali: Setelah tautan utama elementshilang, semua referensi bundar akan di-GCed. Jika elemen Anda menahan referensi ke elemen yang tidak diperlukan, maka perbaiki kode dan setel ref ke nol ketika Anda selesai menggunakannya. Itu akan GCed. Peta kelemahan tidak diperlukan .
Pacerier
2
@Pacerier terima kasih atas umpan balik Anda yang antusias, namun pengaturan elementske null tidak akan mengizinkan browser untuk menambahkan elemen dalam situasi cuplikan pertama. Ini karena Anda menetapkan properti khusus pada elemen, dan kemudian elemen-elemen itu masih dapat diperoleh, dan properti kustom mereka masih dapat diakses, sehingga mencegah salah satu dari mereka dari menjadi GC'ed. Anggap saja seperti rantai cincin logam. Solongas Anda memiliki akses ke setidaknya satu tautan di rantai, Anda dapat memegang tautan itu di rantai, dan dengan demikian mencegah seluruh rantai barang agar tidak jatuh ke jurang.
Jack Giffin
1
kode produksi dengan vault yang bernama vars make me vomit
Barbu Barbu
10

Saya menggunakan WeakMapuntuk cache dari memoisasi bebas khawatir dari fungsi yang mengambil objek tidak berubah sebagai parameternya.

Memoisasi adalah cara yang bagus untuk mengatakan "setelah Anda menghitung nilai, simpanlah sehingga Anda tidak perlu menghitungnya lagi".

Ini sebuah contoh:

Beberapa hal yang perlu diperhatikan:

  • Objek Immutable.js mengembalikan objek baru (dengan pointer baru) saat Anda memodifikasinya sehingga menggunakannya sebagai kunci dalam WeakMap adalah menjamin nilai yang dihitung sama.
  • WeakMap sangat bagus untuk memo karena begitu objek (digunakan sebagai kunci) mendapat sampah yang dikumpulkan, demikian juga nilai yang dihitung pada WeakMap.
Rico Kahler
sumber
1
Ini adalah penggunaan yang valid dari peta lemah selama cache memoisasi dimaksudkan untuk menjadi peka terhadap memori , tidak persisten sepanjang umur objek / fungsi. Jika "cache memoisasi" dimaksudkan untuk bertahan selama umur objek / fungsi, makamap lemah adalah pilihan yang salah: Gunakan salah satu dari 6 teknik enkapsulasi javascript default sebagai gantinya.
Pacerier
3

Saya memiliki case use berdasarkan fitur sederhana ini / Contoh untuk WeakMaps.

MENGELOLA KOLEKSI PENGGUNA

Aku mulai dengan UserObyek yang sifat termasuk fullname, username, age, genderdan metode yang disebut printyang mencetak ringkasan dibaca manusia dari sifat-sifat lainnya.

/**
Basic User Object with common properties.
*/
function User(username, fullname, age, gender) {
    this.username = username;
    this.fullname = fullname;
    this.age = age;
    this.gender = gender;
    this.print = () => console.log(`${this.fullname} is a ${age} year old ${gender}`);
}

Saya kemudian menambahkan Peta yang dipanggil usersuntuk menyimpan koleksi beberapa pengguna yang dikunci oleh username.

/**
Collection of Users, keyed by username.
*/
var users = new Map();

Penambahan Koleksi juga membutuhkan fungsi pembantu untuk menambah, mendapatkan, menghapus Pengguna dan bahkan fungsi untuk mencetak semua pengguna demi kelengkapan.

/**
Creates an User Object and adds it to the users Collection.
*/
var addUser = (username, fullname, age, gender) => {
    let an_user = new User(username, fullname, age, gender);
    users.set(username, an_user);
}

/**
Returns an User Object associated with the given username in the Collection.
*/
var getUser = (username) => {
    return users.get(username);
}

/**
Deletes an User Object associated with the given username in the Collection.
*/
var deleteUser = (username) => {
    users.delete(username);
}

/**
Prints summary of all the User Objects in the Collection.
*/
var printUsers = () => {
    users.forEach((user) => {
        user.print();
    });
}

Dengan semua kode di atas berjalan, katakanlah NodeJS , hanya usersPeta yang memiliki referensi ke Objek Pengguna dalam seluruh proses. Tidak ada referensi lain untuk masing-masing Objek Pengguna.

Menjalankan kode ini sebagai shell NodeJS interaktif, seperti Contoh saya menambahkan empat pengguna dan mencetaknya: Menambah dan mencetak pengguna

TAMBAHKAN INFO LEBIH LANJUT UNTUK PENGGUNA TANPA MEMODIFIKASI KODE YANG ADA

Sekarang katakanlah fitur baru diperlukan di mana setiap pengguna tautan Platform Media Sosial (SMP) perlu dilacak bersama dengan Objek Pengguna.

Kuncinya di sini adalah juga bahwa fitur ini harus diimplementasikan dengan intervensi minimal terhadap kode yang ada.

Ini dimungkinkan dengan WeakMaps dengan cara berikut.

Saya menambahkan tiga WeakMaps terpisah untuk Twitter, Facebook, LinkedIn.

/*
WeakMaps for Social Media Platforms (SMPs).
Could be replaced by a single Map which can grow
dynamically based on different SMP names . . . anyway...
*/
var sm_platform_twitter = new WeakMap();
var sm_platform_facebook = new WeakMap();
var sm_platform_linkedin = new WeakMap();

Fungsi pembantu, getSMPWeakMapditambahkan hanya untuk mengembalikan WeakMap yang terkait dengan nama SMP yang diberikan.

/**
Returns the WeakMap for the given SMP.
*/
var getSMPWeakMap = (sm_platform) => {
    if(sm_platform == "Twitter") {
        return sm_platform_twitter;
    }
    else if(sm_platform == "Facebook") {
        return sm_platform_facebook;
    }
    else if(sm_platform == "LinkedIn") {
        return sm_platform_linkedin;
    }
    return undefined;
}

Fungsi untuk menambahkan tautan SMP pengguna ke SMP WeakMap yang diberikan.

/**
Adds a SMP link associated with a given User. The User must be already added to the Collection.
*/
var addUserSocialMediaLink = (username, sm_platform, sm_link) => {
    let user = getUser(username);
    let sm_platform_weakmap = getSMPWeakMap(sm_platform);
    if(user && sm_platform_weakmap) {
        sm_platform_weakmap.set(user, sm_link);
    }
}

Fungsi untuk mencetak hanya pengguna yang hadir di SMP yang diberikan.

/**
Prints the User's fullname and corresponding SMP link of only those Users which are on the given SMP.
*/
var printSMPUsers = (sm_platform) => {
    let sm_platform_weakmap = getSMPWeakMap(sm_platform);
    console.log(`Users of ${sm_platform}:`)
    users.forEach((user)=>{
        if(sm_platform_weakmap.has(user)) {
            console.log(`\t${user.fullname} : ${sm_platform_weakmap.get(user)}`)
        }
    });
}

Anda sekarang dapat menambahkan tautan SMP untuk para pengguna, juga dengan kemungkinan setiap pengguna memiliki tautan pada beberapa SMP.

... melanjutkan dengan Contoh sebelumnya, saya menambahkan tautan SMP ke pengguna, banyak tautan untuk pengguna, Bill dan Sarah, lalu mencetak tautan untuk setiap SMP secara terpisah: Menambahkan tautan SMP ke pengguna dan menampilkannya

Sekarang katakanlah seorang Pengguna dihapus dari usersPeta dengan menelepon deleteUser. Itu menghapus satu-satunya referensi ke Objek Pengguna. Ini pada gilirannya juga akan menghapus tautan SMP dari semua / semua SMP WeakMaps (oleh Garbage Collection) karena tanpa Objek Pengguna tidak ada cara untuk mengakses tautan SMP mana pun.

... melanjutkan dengan Contoh, saya menghapus Bill pengguna dan kemudian mencetak tautan SMP yang dikaitkan dengannya:

Menghapus Bill pengguna dari Peta juga menghapus tautan SMP

Tidak ada persyaratan kode tambahan untuk menghapus tautan SMP secara terpisah dan kode yang ada sebelum fitur ini tidak dimodifikasi.

Jika ada cara lain untuk menambahkan fitur ini dengan / tanpa WeakMaps, jangan ragu untuk berkomentar.

electrocrat
sumber
_____nice______
Aleks