如何扩展 Array.prototype.push()?

IT技术 javascript arrays prototype array-push
2021-02-05 17:19:47

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

我不太确定如何做到这一点,但这里有一些我一直在玩但没有成功的代码。

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

    //callback method goes here

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

arr.push('test');
6个回答

由于push允许推送多个元素,我使用下面参数变量让真正的 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);
    };
})();
当分配给Array.prototype.push,你必须要非常小心什么进入//Do what you want here代码。如果其中的任何内容导致调用Array.push()(甚至是间接调用),您将因堆栈溢出而导致 JavaScript 崩溃。
2021-03-18 17:19:47
我只是想强调你的推荐信息,指出忽视它是多么容易引起严重的不愉快。
2021-04-04 17:19:47
@pottedmeat:但它的可读性较差 - 请记住,程序不仅是为机器编写的,也是为其他程序员编写的!
2021-04-07 17:19:47
@some 非常感谢您对原型的清晰解释,而不是!
2021-04-08 17:19:47
伟大的!那么基于索引的分配呢?为什么没有可以引发事件的 set(index) 或其他方法?
2021-04-14 17:19:47

首先你需要子类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 变了。
2021-04-12 17:19:47

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;
};

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

你可以这样做:

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);
2021-03-17 17:19:47

还有另一种更原生的方法来实现这一点: 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);