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

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

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

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

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


person commonpike    schedule 04.09.2015    source источник
comment
Нет, слабые карты не являются итерируемыми. Консоль творит чудеса (эй, она также показывает значения промисов синхронно).   -  person Bergi    schedule 04.09.2015
comment
ОК - я хочу сделать это волшебство, есть предложения? :-Д   -  person commonpike    schedule 04.09.2015
comment
Затем напишите приложение, использующее интерфейс отладки :-)   -  person Bergi    schedule 04.09.2015
comment
необходимые функции доступны только для привилегированного кода. javascript, выполняемый в ненадежных контекстах, не может перечислять слабые карты.   -  person the8472    schedule 05.09.2015
comment
@bergi - это действительно хорошая идея, спасибо :-)   -  person commonpike    schedule 06.09.2015


Ответы (3)


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

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

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

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

person Bergi    schedule 12.09.2015
comment
С тех пор, как я прочитал этот ответ, я начал замечать более странную магию в консоли Chrome. Бывают редкие ситуации, когда консоль при попытке трассировки кода может выводить данные и из будущего :-) - person commonpike; 31.05.2016
comment
@commonpike: это конкретное поведение объясняется здесь. - person Bergi; 31.05.2016
comment
Они выглядят как ценности из будущего относительно прошлого, но не дальше настоящего. :} - person trusktr; 21.03.2017

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

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

person Franck Freiburger    schedule 14.11.2019

Забегая далеко вперед с квалификатором в вашем вопросе (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));
    }
  }
}

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

person Ed_Johnsen    schedule 20.06.2021