Я пытаюсь случайным образом выбрать случайное свойство из объекта, который я использую в качестве словаря для быстрой индексации.
Рассмотрим следующий код:
//Create test dictionary
var dict = {};
for(var i = 0; i < 10000; i++) {
var num = Math.random() * 1000000 << 0;
dict[num] = { Id: num };
}
//Fuzz
const NUM_RUNS = 1000;
var start = new Date();
for(var i = 0; i < NUM_RUNS; i++)
getRandom(dict);
var end = new Date();
var runTime = (end.getTime() - start.getTime()) / 1000;
var timePerCall = (runTime / NUM_RUNS) * Math.pow(10,9);
console.info('Total Calls: ' + NUM_RUNS);
console.info('Total Runtime: ' + runTime + ' seconds');
console.info('Time Per Call: ' + timePerCall + ' nanoseconds');
function getRandom(dict) {
var keys = Object.keys(dict);
var index = keys[Math.random() * keys.length << 0];
return dict[index];
}Как видите, использование Object.keys() требует больших затрат на очень, особенно по мере роста словаря.
Я ищу оптимальный способ добиться случайного выбора элемента в словаре. Конечно, наличие 10000+ элементов в словаре - крайний случай, но, тем не менее, я хотел бы иметь возможность справиться с этим.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Если кэширование массива Object.keys невозможно, вы можете сохранить свою собственную копию с помощью Proxy:
function generateKeyTracker (keysPropertyName) {
const set = new Set();
function defineProperty (target, property, descriptor) {
target[property] = descriptor.value;
if (set.has(property)) return true;
set.add(property);
target[keysPropertyName].push(property);
return true;
}
function deleteProperty (target, property) {
delete target[property];
if (!set.delete(property)) return true;
target[keysPropertyName] = target[keysPropertyName].filter(key => key !== property);
return true;
}
return {defineProperty, deleteProperty};
}
//Create test dictionary
var dict = new Proxy(
Object.defineProperty({}, '__keys', {
configurable: true,
enumerable: false,
writable: true,
value: []
}),
generateKeyTracker('__keys')
);
for(var i = 0; i < 1e4; i++) {
var num = Math.random() * 1e6 << 0;
dict[num] = { Id: num };
}
//Fuzz
const NUM_RUNS = 1e6;
var start = performance.now();
for(var i = 0; i < NUM_RUNS; i++)
getRandom(dict);
var end = performance.now();
var runTime = end - start;
var timePerCall = (runTime / NUM_RUNS);
console.info(`Total Calls: ${NUM_RUNS}`);
console.info(`Total Runtime: ${runTime} ms`);
console.info(`Time Per Call: ${timePerCall * 1e6} ns`);
function getRandom(dict) {
var index = Math.random() * dict.__keys.length << 0;
return dict[dict.__keys[index]];
}При этом используются ловушки на создание собственности и удаление для отслеживания ключей свойств dict, которые хранятся в свойстве dict.__keysне перечислимый.