简体   繁体   English

最大的数组我可以安全地传递给function.apply()/ spread运算符

[英]Largest array I can safely pass to function.apply() / spread operator

The "JavaScriptonic" way to calculate the maximum value of an array is: 计算数组最大值的“JavaScriptonic”方法是:

Math.max.apply(null, array)

However, this errors with "maximum call stack size exceeded" on arrays of size 2^16 (Chrome, Safari) or 2^18 (Firefox). 但是,在大小为2 ^ 16(Chrome,Safari)或2 ^ 18(Firefox)的阵列上出现“超出最大调用堆栈大小”的错误。 See https://jsfiddle.net/dxcot206/ https://jsfiddle.net/dxcot206/

How can I use this technique safely? 我怎样才能安全地使用这种技术? Is there a largest array length for which this technique is guaranteed to work? 是否有最大的阵列长度可以保证这种技术有效?

Might the answer be different in a WebWorker, since background threads often have smaller stack sizes? 在WebWorker中,答案可能会有所不同,因为后台线程通常具有较小的堆栈大小?

How can I use this technique safely? 我怎样才能安全地使用这种技术?

Not at all. 一点也不。

Is there a largest array length for which this technique is guaranteed to work? 是否有最大的阵列长度可以保证这种技术有效?

No, there are no requirements for such things in the spec, all you are seeing are implementation-dependent " we don't support unreasonably large argument lists above N " restrictions. 不,规范中没有对此类内容的要求,您所看到的都是依赖于实现的“ 我们不支持超过N无理大型参数列表 ”限制。

The "JavaScriptonic" way to calculate the maximum value of an array is: Math.max.apply(null, array) 计算数组最大值的“JavaScriptonic”方法是: Math.max.apply(null, array)

It's just short, but not very efficient, and as you have seen might not work. 它只是短暂的,但效率不高,而且你所看到的可能不起作用。 Better use array.reduce((a, b) => Math.max(a, b)) . 最好使用array.reduce((a, b) => Math.max(a, b))

Is there a largest array length for which this technique is guaranteed to work? 是否有最大的阵列长度可以保证这种技术有效? Might the answer be different in a WebWorker, since background threads often have smaller stack sizes? 在WebWorker中,答案可能会有所不同,因为后台线程通常具有较小的堆栈大小?

To help answer your second (2) questions in a particular environment, here's a script you can run that uses a binary search to figure out the answer: 为了帮助回答特定环境中的第二(2)个问题,这里是一个可以运行的脚本,它使用二进制搜索来找出答案:

(function () {
  // Returns whether or not the action threw an exception.
  function throwsException(action) {
    try {
      action();
    } catch (e) {
      return true;
    }
    return false;
  }

  // Performs the action for various values between lower and upper and returns
  // the maximum value for the action to return true.
  function findMaxValueForAction(action, lower, upper) {
    var best;

    while (upper - lower > 1) {
      var previousUpper = upper;

      var guess = Math.floor((lower + upper) / 2);
      if (action(guess)) {
        // If the action is successful then the lower needs to be updated to what just succeeded. 
        lower = guess;
        // Is the (successful) lower better than the current best?
        if (best === undefined || lower > best) {
          // If so update the current best.
          best = lower;
        }
      } else {
        // If the action was unsuccessful the new upper bound is 1 less than what we just tried.
        upper = guess - 1;
      }
    }

    return best;
  }

  var maxArraySize = findMaxValueForAction(function (value) {    
    return !throwsException(function () {
      var array = new Array(value);
    });
  }, 0, Number.MAX_SAFE_INTEGER);

  var maxArrayApplySize = findMaxValueForAction(function (value) {
    return !throwsException(function () {
      var array = new Array(value);
      Math.max.apply(null, array);
    });
  }, 0, maxArraySize);

  return [
    'Max "value" for "new Array(value)": ' + maxArraySize, 
    'Max "value" for "Math.max.apply(null, new Array(value))": ' + maxArrayApplySize
  ];
})().forEach(function(message) { console.log(message) });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM