首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用JavaScript跟踪对象键的有效方法

使用JavaScript跟踪对象键的有效方法
EN

Stack Overflow用户
提问于 2018-08-14 03:07:02
回答 2查看 239关注 0票数 3

我使用一个带有陷阱的Proxy对象来跟踪对象键,这样我就可以很容易地迭代和/或从对象中选择一个随机键,而性能开销很小。目前,我在添加键时将其存储在数组中。这对于插入和随机选择非常有效,但是当属性被删除时,开销是巨大的:

代码语言:javascript
复制
// Benchmark
var testObject = createProxy();

var start = performance.now();

for( var i = 0; i < 1e4; i++ )
  testObject[Math.random() * 1e6 << 0] = true;
for( var i in testObject )
  if( i[0] !== '_' )
    delete testObject[ i ];
    
var end = performance.now();

var total = ( end - start );
console.log( 'Test took ' + total + ' ms' );

// Implementation
function createProxy() {
  function keyTracker() {
    const set = new Set();
    function defineProperty( target, property, descriptor ) {
      target[property] = descriptor.value;
      if( property[0] === '_' ) return true;
      if( set.has( property ) ) return true;
      
      set.add( property );
      target[ '__keys' ].push( property );
      return true;
    }
    function deleteProperty( target, property ) {
      if( property[ 0 ] === '_' ) return true;
      
      delete target[ property ];
      if( !set.delete( property ) ) return true;
      
      target[ '__keys' ] = target[ '__keys' ].filter( 
        key => key !== property
      );
      return true;
    }
    return { defineProperty, deleteProperty };
  }
  
  var proxy = new Proxy(
    Object.defineProperty( {}, '__keys', {
     configurable: true,
     enumerable: false,
     writable: true,
     value: []
  } ), keyTracker() );
  
  return proxy;
}

随着对象中键数量的增加,调用Array.filter()的开销会呈指数级增长。我正在寻找一种解决方案,它能够让我避免调用它来删除单个元素。

有没有一种方法可以重新设计,允许O(1)插入、随机选择和删除键?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-08-14 03:31:51

您可以使用排序数组,然后使用二进制搜索来实现O(log )

代码语言:javascript
复制
// Benchmark
Array.prototype.binarySearch = function (target, comparator) {
    var l = 0,
        h = this.length - 1,
        m, comparison;
    comparator = comparator || function (a, b) {
        return (a < b ? -1 : (a > b ? 1 : 0)); /* default comparison method if one was not provided */
    };
    while (l <= h) {
        m = (l + h) >>> 1; /* equivalent to Math.floor((l + h) / 2) but faster */
        comparison = comparator(this[m], target);
        if (comparison < 0) {
            l = m + 1;
        } else if (comparison > 0) {
            h = m - 1;
        } else {
            return m;
        }
    }
    return~l;
};
Array.prototype.binaryInsert = function (target, duplicate, comparator) {
    var i = this.binarySearch(target, comparator);
    if (i >= 0) { /* if the binarySearch return value was zero or positive, a matching object was found */
        if (!duplicate) {
            return i;
        }
    } else { /* if the return value was negative, the bitwise complement of the return value is the correct index for this object */
        i = ~i;
    }
    this.splice(i, 0, target);
    return i;
};
Array.prototype.binaryDelete = function (target, duplicate, comparator) {
    var i = this.binarySearch(target, comparator);
    if (i >= 0) { /* if the binarySearch return value was zero or positive, a matching object was found */
    this.slice(i,1)
    }
    return i;
};
var testObject = createProxy();

var start = performance.now();

for( var i = 0; i < 1e4; i++ )
  testObject[Math.random() * 1e6 << 0] = true;
for( var i in testObject )
  if( i[0] !== '_' )
    delete testObject[ i ];
    
var end = performance.now();

var total = ( end - start );
console.log( 'Test took ' + total + ' ms' );

// Implementation
function createProxy() {
  function keyTracker() {
    const set = new Set();
    function defineProperty( target, property, descriptor ) {
      target[property] = descriptor.value;
      if( property[0] === '_' ) return true;
      if( set.has( property ) ) return true;
      
      set.add( property );
      target[ '__keys' ].binaryInsert( property );
      return true;
    }
    function deleteProperty( target, property ) {
      if( property[ 0 ] === '_' ) return true;
      
      delete target[ property ];
      if( !set.delete( property ) ) return true;
      
      target[ '__keys' ].binaryDelete(property)
      return true;
    }
    return { defineProperty, deleteProperty };
  }
  
  var proxy = new Proxy(
    Object.defineProperty( {}, '__keys', {
     configurable: true,
     enumerable: false,
     writable: true,
     value: []
  } ), keyTracker() );
  
  return proxy;
}

使用从这里植入的二进制搜索javascript-binary-search

票数 2
EN

Stack Overflow用户

发布于 2018-08-14 03:31:33

你可以直接使用splice。它会把你的速度降低800-1000毫秒。

代码语言:javascript
复制
       target[ '__keys' ].splice(target[ '__keys' ].indexOf(property), 1);

代码语言:javascript
复制
// Benchmark
var testObject = createProxy();

var start = performance.now();

for( var i = 0; i < 1e4; i++ )
  testObject[Math.random() * 1e6 << 0] = true;
for( var i in testObject )
  if( i[0] !== '_' )
    delete testObject[ i ];
    
var end = performance.now();

var total = ( end - start );
console.log( 'Test took ' + total + ' ms' );

// Implementation
function createProxy() {
  function keyTracker() {
    const set = new Set();
    function defineProperty( target, property, descriptor ) {
      target[property] = descriptor.value;
      if( property[0] === '_' ) return true;
      if( set.has( property ) ) return true;
      
      set.add( property );
      target[ '__keys' ].push( property );
      return true;
    }
    function deleteProperty( target, property ) {
      if( property[ 0 ] === '_' ) return true;
      
      delete target[ property ];
      if( !set.delete( property ) ) return true;
      
      target[ '__keys' ]
      .splice(target[ '__keys' ].indexOf(property), 1);
      return true;
    }
    return { defineProperty, deleteProperty };
  }
  
  var proxy = new Proxy(
    Object.defineProperty( {}, '__keys', {
     configurable: true,
     enumerable: false,
     writable: true,
     value: []
  } ), keyTracker() );
  
  return proxy;
}

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51829020

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档