Как перебрать слабую карту?

Слабая карта JavaScript ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) не позволяет получить ключ, длину или размер в зависимости от конструкции.

Возможно ли, тем не менее, зацикливать записи каким-то образом?

Если нет.. как консоль Chrome делает это?

введите описание изображения здесь

4 ответа

Решение

Возможно ли, тем не менее, зацикливать записи каким-то образом?

Нет, как вы говорите, содержимое WeakMap не доступны по дизайну, и нет повторяемости.

Если нет... как консоль Chrome делает это?

Консоль использует API отладки движка JS, который обеспечивает доступ к внутренним объектам (также для обещания состояний, обернутых примитивов и т. Д.) И многим другим.

Дело движется, и скоро станет возможным создавать повторяющиеся недельные карты благодаря слабым ссылкам. См. Повторяющийся пример WeakMap в предложении tc39 weakrefs.

(обратите внимание, что это уже возможно с nodejs v12.?.? используя --harmony-weak-refs флаг)

Вы можете использовать этот маленький фрагмент для универсального forEach. Однако он использует lodash и может быть значительно улучшен.

import lodashForEach from 'lodash/forEach';
import entries from 'lodash/entries';
/**
 * @since lodash@4.17.3
 * @param {Array|Map|Object|Set|WeakMap|WeakSet} iterable
 * @param {Function} iteratee
 * @example
 * const iterable = new Map();
 * iterable.set('somekey1', 1);
 * iterable.set('somekey2', 2);
 * // or
 * const iterable = new Set();
 * iterable.add("entry1");
 * iterable.add("entry2");
 * // run function
 * forEach(iterable, (value, key) => {
 *   console.group('-');
 *   console.info('KEY');
 *   console.log(key);
 *   console.info('VALUE');
 *   console.log(value);
 *   console.groupEnd();
 * });
 */
function forEach(iterable, iteratee) {
    lodashForEach((iterable instanceof Set || iterable instanceof WeakSet) ? Array.from(iterable) : entries(iterable), (entry, index, collection) => {
      iteratee(entry[1], entry[0], collection, index);
    });
    return iterable;
}

export default forEach;

ОБНОВИТЬ

После долгого времени я нашел этот ответ неверным. Дело в том, что в старой версии библиотеки polyfill core-js исправлена ​​ошибка, из-за которой она заменяла собственную реализацию WeakMap своей собственной. Поэтому мое решение не подходит для современных браузеров.

function forEach(iterable, iteratee) {
    switch (true) {
        case Array.isArray(iterable) || iterable instanceof Map:
            iterable.forEach(iteratee);
            break;
        case iterable instanceof Set:
            Array.from(iterable).forEach(iteratee);
            break;
        case iterable instanceof WeakMap || iterable instanceof WeakSet:
            // some kind of warning
            break;
        default:
            Object.keys(iterable).forEach((key) => iteratee.call(null, iterable[key], key));
            break;
    }
    return iterable;
}

Забегая далеко с квалификатором в вашем (2015) вопросе, а именно:

Можно ли каким-то образом перебрать записи?

Да.

В одной нелепой ситуации можно сымитировать, а затем перебрать ключи и значения WeakMap, а также сделать правильную независимую копию WeakMap.

Если WeakMap, который вы хотите клонировать, был построен очень специфическим образом с помощью функции-конструктора, вы можете сделать это:

      
// Define a Constructor-Function
// that makes objects
// containing WeakMaps:
function makeWeakMapObject(){
  this.wm1 = new WeakMap();
  this.o1 = {};
  this.o2 = {"orange":"orange"};
  this.wm1.set(this.o1, 37);
  this.wm1.set(this.o2, 'azerty');
}

// Construct a new object:
let constructedWeakMapObject = new makeWeakMapObject();

// Then set a new key-value pair
// on the WeakMap in your object;
// because, ya know, otherwise you'd
// just reuse the WeakMap constructor
// and wouldn't need to clone :D
constructedWeakMapObject.added = {"ya":"glad"};
constructedWeakMapObject.wm1.set(constructedWeakMapObject.added, 42);


// In preparation to clone your newly constructed object,
// get that newly constructed object's property descriptors:
let props = Object.getOwnPropertyDescriptors(constructedWeakMapObject);
// Have a gander at those props; just for fun:
console.log({"props":props});


// Attempt to clone the constructedWeakMapObject
// using its ownPropertyDescriptors
let weakClone = new cloneWeak(props);
// and then check out what you made:
console.log({"weakClone":weakClone});


// Verify that you've made an independent clone
// (even though this example is shallow)
// by altering the WeakMap in your weakClone:
weakClone.wm.delete(weakClone.o1);
// Make sure your clone was altered:
console.log(weakClone.wm.get(weakClone.o1));

// And then check to see that the
// changes to your clone 
// don't appear on your constructed object:
console.log(constructedWeakMapObject);
console.log(constructedWeakMapObject.wm1.get(constructedWeakMapObject.o1));

// A support function to help you use fresh keys in your cloned WeakMap to keep it independent from your original WeakMap
function cloneObject(obj) { // use something more robust, like underscore: _.cloneDeep(obj); actually, you'll likely have to roll your own so you can make clones of functions... anywho
    var clone = {};
    for(var i in obj) {
        if(typeof(obj[i])==="object" && obj[i] !== null)
            clone[i] = cloneObject(obj[i]);
        else
            clone[i] = obj[i];
    }
    return clone;
}

// Called as a constructor function w/arguments
function cloneWeak(inco){ // a bit wonky, at least in the middle
  
  this.wm = new WeakMap();

  let tempMap;
  
  for(key in inco){
    // Build keys on 'this' that match the incoming keys
    if(Object.prototype.toString.call(inco[key].value) !== "[object WeakMap]"){
    
        this[key] = cloneObject(inco[key].value);
    }
    // Reference the incoming map from your temp map
    // (this makes the following loop possible)
    else{tempMap = inco[key].value;}
  }
  
  this.fakeForHack = {}; // no idea why this works
  this.wm.set(this.fakeForHack, "ok"); // no idea why this works... without it, the WeakMap entry for made.wm1.get(made.added) won't transfer -> ???
  
  for(key in inco){
    
    if(Object.prototype.toString.call(inco[key].value) !== "[object WeakMap]"){
      // Set values for 'this' WeakMap:
      this.wm.set(this[key], tempMap.get(inco[key].value));
    }
  }
}

Это уродливо, хрупко и решает только нелепый крайний случай; пожалуйста!

Другие вопросы по тегам