【问题标题】:How can I extend Array.prototype.push()?如何扩展 Array.prototype.push()?
【发布时间】:2010-10-09 00:38:08
【问题描述】:

我正在尝试扩展Array.push 方法,以便使用push 将触发回调方法,然后执行正常的数组函数。

我不太确定如何执行此操作,但这里有一些我一直在尝试但没有成功的代码。

arr = [];
arr.push = function(data){

    //callback method goes here

    this = Array.push(data);
    return this.length;
}

arr.push('test');

【问题讨论】:

    标签: javascript arrays prototype array-push


    【解决方案1】:

    由于 push 允许推送多个元素,我使用下面的 arguments 变量让真正的 push 方法拥有所有参数。

    此解决方案仅影响 arr 变量:

    arr.push = function () {
        //Do what you want here...
        return Array.prototype.push.apply(this, arguments);
    }
    

    此解决方案会影响所有数组。我不建议你这样做。

    Array.prototype.push = (function() {
        var original = Array.prototype.push;
        return function() {
            //Do what you want here.
            return original.apply(this, arguments);
        };
    })();
    

    【讨论】:

    • @pottedmeat:但它的可读性较差 - 请记住,程序不仅是为机器编写的,也是为其他程序员编写的!
    • @some 非常感谢您对原型的清晰解释!
    • 分配给Array.prototype.push 时,您必须非常小心了解//Do what you want here 代码中的内容。如果其中的任何内容导致对Array.push() 的调用(甚至是间接调用),您将导致 JavaScript 因堆栈溢出而崩溃。
    • 我只是想强调你的推荐信息,指出忽视它很容易引起严重的不愉快。
    • 太棒了!那么基于索引的赋值呢?为什么没有可以引发事件的 set(index) 或其他方法?
    【解决方案2】:

    首先你需要子类Array:

    ES6 (https://kangax.github.io/compat-table/es6/):

    class SortedArray extends Array {
        constructor(...args) {
            super(...args);
        }
        push() {
            return super.push(arguments);
        }
    }
    

    ES5(proto 几乎已被弃用,但它是目前唯一的解决方案):

    function SortedArray() {
        var arr = [];
        arr.push.apply(arr, arguments);
        arr.__proto__ = SortedArray.prototype;
        return arr;
    }
    SortedArray.prototype = Object.create(Array.prototype);
    
    SortedArray.prototype.push = function() {
        this.arr.push(arguments);
    };
    

    【讨论】:

    • 好奇为什么有人不这样做? JS 变了。
    【解决方案3】:

    Array.prototype.push 是在 JavaScript 1.2 中引入的。真的就这么简单:

    Array.prototype.push = function() {
        for( var i = 0, l = arguments.length; i < l; i++ ) this[this.length] = arguments[i];
        return this.length;
    };
    

    你总是可以在前面添加一些东西。

    【讨论】:

      【解决方案4】:

      你可以这样做:

      arr = []
      arr.push = function(data) {
        alert(data); //callback
      
        return Array.prototype.push.call(this, data);
      }
      

      如果您遇到没有电话的情况,您也可以选择这个解决方案:

      arr.push = function(data) {
        alert(data); //callback
        
        //While unlikely, someone may be using "psh" to store something important
        //So we save it.
        var saved = this.psh;
        this.psh = Array.prototype.push;
        var ret = this.psh(data);
        this.psh = saved;
        return ret;
      }
      

      虽然我告诉你怎么做,但你可能会更好地使用执行回调的不同方法,然后只在数组上调用 push 而不是覆盖 push 。您最终可能会遇到一些意想不到的副作用。例如,push 似乎是可变参数(接受可变数量的参数,如 printf),使用上述方法会破坏这一点。

      您需要弄乱 _Arguments() 和 _ArgumentsLength() 才能正确覆盖此函数。我强烈反对这条路线。

      或者您可以使用“参数”,这也可以。不过,我仍然建议不要走这条路。

      【讨论】:

      • Array.prototype.push.call(this, data);不能工作,因为 Array 可以接受多个项目。 Array.prototype.push.apply(this, arguments);
      【解决方案5】:

      还有另一种更原生的方法来实现这一点:Proxy

      const target = [];
      
      const handler = {
        set: function(array, index, value) {
          // Call callback function here
      
          // The default behavior to store the value
          array[index] = value;
      
          // Indicate success
          return true;
        }
      };
      
      const proxyArray = new Proxy(target, handler);
      

      【讨论】:

        【解决方案6】:

        我想在对象被推送到数组之后调用一个函数,所以我做了以下操作:

        myArray.push = function() { 
            Array.prototype.push.apply(this, arguments);
            myFunction();
            return myArray.length;
        };
        
        function myFunction() {
            for (var i = 0; i < myArray.length; i++) {
                //doSomething;
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-06-22
          • 2018-08-22
          • 2011-06-09
          • 2014-01-28
          • 2016-09-25
          • 2012-02-16
          • 2012-01-24
          相关资源
          最近更新 更多