จะดูการเปลี่ยนแปลงอาร์เรย์ได้อย่างไร?


111

ใน Javascript มีวิธีการแจ้งเตือนเมื่อมีการแก้ไขอาร์เรย์โดยใช้การกำหนดแบบพุชป๊อปกะหรือดัชนีหรือไม่ ฉันต้องการสิ่งที่จะจุดไฟให้เหตุการณ์ที่ฉันสามารถจัดการได้

ฉันรู้เกี่ยวกับwatch()ฟังก์ชันการทำงานใน SpiderMonkey แต่จะใช้ได้ก็ต่อเมื่อตัวแปรทั้งหมดถูกตั้งค่าเป็นอย่างอื่น

คำตอบ:


174

มีไม่กี่ตัวเลือก ...

1. แทนที่วิธีการผลักดัน

ไปตามเส้นทางที่รวดเร็วและสกปรกคุณสามารถแทนที่เมธอด `push () 'สำหรับอาร์เรย์ของคุณ1 :
Object.defineProperty(myArray, "push", {
  enumerable: false, // hide from for...in
  configurable: false, // prevent further meddling...
  writable: false, // see above ^
  value: function () {
    for (var i = 0, n = this.length, l = arguments.length; i < l; i++, n++) {          
      RaiseMyEvent(this, n, this[n] = arguments[i]); // assign/raise your event
    }
    return n;
  }
});

1หรือหากคุณต้องการกำหนดเป้าหมายอาร์เรย์ทั้งหมดคุณสามารถลบล้างArray.prototype.push()ได้ ใช้ความระมัดระวังแม้ว่า; โค้ดอื่น ๆ ในสภาพแวดล้อมของคุณอาจไม่ชอบหรือคาดหวังการแก้ไขแบบนั้น ยังถ้าจับเป็นเสียงที่น่าสนใจเพียงแทนที่ด้วยmyArrayArray.prototype

ตอนนี้เป็นเพียงวิธีการเดียวและมีหลายวิธีในการเปลี่ยนเนื้อหาอาร์เรย์ เราคงต้องการอะไรที่ครอบคลุมมากกว่านี้ ...

2. สร้างอาร์เรย์ที่สังเกตได้ที่กำหนดเอง

แทนที่จะลบล้างวิธีการคุณสามารถสร้างอาร์เรย์ที่สังเกตได้ของคุณเอง การใช้งานเฉพาะนี้คัดลอกอาร์เรย์ไปยังอ็อบเจ็กต์ที่เหมือนอาร์เรย์ใหม่และจัดเตรียม `push () ',` pop ()', `` shift () `,ʻunshift ()`, `slice ()` และ `splice ( ) `วิธีการ ** และ ** ตัวเข้าถึงดัชนีที่กำหนดเอง (โดยมีเงื่อนไขว่าขนาดอาร์เรย์จะถูกแก้ไขโดยใช้วิธีการใดวิธีการหนึ่งหรือคุณสมบัติ" ความยาว "เท่านั้น)

function ObservableArray(items) {
  var _self = this,
    _array = [],
    _handlers = {
      itemadded: [],
      itemremoved: [],
      itemset: []
    };

  function defineIndexProperty(index) {
    if (!(index in _self)) {
      Object.defineProperty(_self, index, {
        configurable: true,
        enumerable: true,
        get: function() {
          return _array[index];
        },
        set: function(v) {
          _array[index] = v;
          raiseEvent({
            type: "itemset",
            index: index,
            item: v
          });
        }
      });
    }
  }

  function raiseEvent(event) {
    _handlers[event.type].forEach(function(h) {
      h.call(_self, event);
    });
  }

  Object.defineProperty(_self, "addEventListener", {
    configurable: false,
    enumerable: false,
    writable: false,
    value: function(eventName, handler) {
      eventName = ("" + eventName).toLowerCase();
      if (!(eventName in _handlers)) throw new Error("Invalid event name.");
      if (typeof handler !== "function") throw new Error("Invalid handler.");
      _handlers[eventName].push(handler);
    }
  });

  Object.defineProperty(_self, "removeEventListener", {
    configurable: false,
    enumerable: false,
    writable: false,
    value: function(eventName, handler) {
      eventName = ("" + eventName).toLowerCase();
      if (!(eventName in _handlers)) throw new Error("Invalid event name.");
      if (typeof handler !== "function") throw new Error("Invalid handler.");
      var h = _handlers[eventName];
      var ln = h.length;
      while (--ln >= 0) {
        if (h[ln] === handler) {
          h.splice(ln, 1);
        }
      }
    }
  });

  Object.defineProperty(_self, "push", {
    configurable: false,
    enumerable: false,
    writable: false,
    value: function() {
      var index;
      for (var i = 0, ln = arguments.length; i < ln; i++) {
        index = _array.length;
        _array.push(arguments[i]);
        defineIndexProperty(index);
        raiseEvent({
          type: "itemadded",
          index: index,
          item: arguments[i]
        });
      }
      return _array.length;
    }
  });

  Object.defineProperty(_self, "pop", {
    configurable: false,
    enumerable: false,
    writable: false,
    value: function() {
      if (_array.length > -1) {
        var index = _array.length - 1,
          item = _array.pop();
        delete _self[index];
        raiseEvent({
          type: "itemremoved",
          index: index,
          item: item
        });
        return item;
      }
    }
  });

  Object.defineProperty(_self, "unshift", {
    configurable: false,
    enumerable: false,
    writable: false,
    value: function() {
      for (var i = 0, ln = arguments.length; i < ln; i++) {
        _array.splice(i, 0, arguments[i]);
        defineIndexProperty(_array.length - 1);
        raiseEvent({
          type: "itemadded",
          index: i,
          item: arguments[i]
        });
      }
      for (; i < _array.length; i++) {
        raiseEvent({
          type: "itemset",
          index: i,
          item: _array[i]
        });
      }
      return _array.length;
    }
  });

  Object.defineProperty(_self, "shift", {
    configurable: false,
    enumerable: false,
    writable: false,
    value: function() {
      if (_array.length > -1) {
        var item = _array.shift();
        delete _self[_array.length];
        raiseEvent({
          type: "itemremoved",
          index: 0,
          item: item
        });
        return item;
      }
    }
  });

  Object.defineProperty(_self, "splice", {
    configurable: false,
    enumerable: false,
    writable: false,
    value: function(index, howMany /*, element1, element2, ... */ ) {
      var removed = [],
          item,
          pos;

      index = index == null ? 0 : index < 0 ? _array.length + index : index;

      howMany = howMany == null ? _array.length - index : howMany > 0 ? howMany : 0;

      while (howMany--) {
        item = _array.splice(index, 1)[0];
        removed.push(item);
        delete _self[_array.length];
        raiseEvent({
          type: "itemremoved",
          index: index + removed.length - 1,
          item: item
        });
      }

      for (var i = 2, ln = arguments.length; i < ln; i++) {
        _array.splice(index, 0, arguments[i]);
        defineIndexProperty(_array.length - 1);
        raiseEvent({
          type: "itemadded",
          index: index,
          item: arguments[i]
        });
        index++;
      }

      return removed;
    }
  });

  Object.defineProperty(_self, "length", {
    configurable: false,
    enumerable: false,
    get: function() {
      return _array.length;
    },
    set: function(value) {
      var n = Number(value);
      var length = _array.length;
      if (n % 1 === 0 && n >= 0) {        
        if (n < length) {
          _self.splice(n);
        } else if (n > length) {
          _self.push.apply(_self, new Array(n - length));
        }
      } else {
        throw new RangeError("Invalid array length");
      }
      _array.length = n;
      return value;
    }
  });

  Object.getOwnPropertyNames(Array.prototype).forEach(function(name) {
    if (!(name in _self)) {
      Object.defineProperty(_self, name, {
        configurable: false,
        enumerable: false,
        writable: false,
        value: Array.prototype[name]
      });
    }
  });

  if (items instanceof Array) {
    _self.push.apply(_self, items);
  }
}

(function testing() {

  var x = new ObservableArray(["a", "b", "c", "d"]);

  console.log("original array: %o", x.slice());

  x.addEventListener("itemadded", function(e) {
    console.log("Added %o at index %d.", e.item, e.index);
  });

  x.addEventListener("itemset", function(e) {
    console.log("Set index %d to %o.", e.index, e.item);
  });

  x.addEventListener("itemremoved", function(e) {
    console.log("Removed %o at index %d.", e.item, e.index);
  });
 
  console.log("popping and unshifting...");
  x.unshift(x.pop());

  console.log("updated array: %o", x.slice());

  console.log("reversing array...");
  console.log("updated array: %o", x.reverse().slice());

  console.log("splicing...");
  x.splice(1, 2, "x");
  console.log("setting index 2...");
  x[2] = "foo";

  console.log("setting length to 10...");
  x.length = 10;
  console.log("updated array: %o", x.slice());

  console.log("setting length to 2...");
  x.length = 2;

  console.log("extracting first element via shift()");
  x.shift();

  console.log("updated array: %o", x.slice());

})();

ดูข้อมูลอ้างอิงObject.defineProperty()

นั่นทำให้เราใกล้ชิดมากขึ้น แต่ก็ยังไม่สามารถพิสูจน์ได้ ... ซึ่งนำเราไปสู่:

3. ผู้รับมอบฉันทะ

Proxyวัตถุมีวิธีการแก้ปัญหาอีกครั้งเพื่อให้เบราว์เซอร์ที่ทันสมัย ช่วยให้คุณสามารถสกัดกั้นการเรียกใช้เมธอด accessors ฯลฯ ที่สำคัญที่สุดคือคุณสามารถทำได้โดยไม่ต้องระบุชื่อคุณสมบัติที่ชัดเจน ... ซึ่งจะช่วยให้คุณทดสอบการเข้าถึง / มอบหมายตามดัชนีโดยพลการ คุณยังสามารถสกัดกั้นการลบคุณสมบัติ พร็อกซีจะช่วยให้คุณตรวจสอบการเปลี่ยนแปลงได้อย่างมีประสิทธิภาพก่อนที่จะตัดสินใจอนุญาต ... นอกเหนือจากการจัดการกับการเปลี่ยนแปลงหลังจากข้อเท็จจริง

นี่คือตัวอย่างที่ถอดออก:

(function() {

  if (!("Proxy" in window)) {
    console.warn("Your browser doesn't support Proxies.");
    return;
  }

  // our backing array
  var array = ["a", "b", "c", "d"];

  // a proxy for our array
  var proxy = new Proxy(array, {
    apply: function(target, thisArg, argumentsList) {
      return thisArg[target].apply(this, argumentList);
    },
    deleteProperty: function(target, property) {
      console.log("Deleted %s", property);
      return true;
    },
    set: function(target, property, value, receiver) {      
      target[property] = value;
      console.log("Set %s to %o", property, value);
      return true;
    }
  });

  console.log("Set a specific index..");
  proxy[0] = "x";

  console.log("Add via push()...");
  proxy.push("z");

  console.log("Add/remove via splice()...");
  proxy.splice(1, 3, "y");

  console.log("Current state of array: %o", array);

})();


ขอบคุณ! ซึ่งใช้ได้กับเมธอดอาร์เรย์ปกติ มีความคิดอย่างไรในการยกระดับเหตุการณ์เช่น "arr [2] =" foo "
Sridatta Thatipamala

4
ฉันเดาว่าคุณสามารถใช้วิธีการset(index)ในต้นแบบของ Array และทำอะไรบางอย่างที่ต่อต้านเชื้อโรคได้
Pablo Fernandez

8
มันจะดีกว่ามากถ้า subclass Array โดยทั่วไปไม่ควรแก้ไขต้นแบบของ Array
Wayne

1
คำตอบที่โดดเด่นที่นี่ คลาสของ ObservableArray นั้นยอดเยี่ยมมาก +1
dooburt

1
"'_array.length === 0 && ลบ _self [ดัชนี];" - อธิบายบรรทัดนี้ได้ไหม
เฝือก

23

จากการอ่านคำตอบทั้งหมดที่นี่ฉันได้รวบรวมโซลูชันที่เรียบง่ายซึ่งไม่ต้องใช้ไลบรารีภายนอกใด ๆ

นอกจากนี้ยังแสดงให้เห็นถึงแนวคิดทั่วไปสำหรับแนวทางนี้ได้ดีขึ้นมาก:

function processQ() {
   // ... this will be called on each .push
}

var myEventsQ = [];
myEventsQ.push = function() { Array.prototype.push.apply(this, arguments);  processQ();};

นี่เป็นความคิดที่ดี แต่คุณไม่คิดว่าถ้าเช่นฉันต้องการใช้สิ่งนี้ในอาร์เรย์ข้อมูลแผนภูมิ js และฉันมีแผนภูมิ 50 ซึ่งหมายถึงอาร์เรย์ 50 อาร์เรย์และแต่ละอาร์เรย์จะได้รับการอัปเดตทุก ๆ วินาที -> ลองนึกภาพขนาดของ อาร์เรย์ 'myEventsQ' ในตอนท้ายของวัน! ฉันคิดว่าเมื่อไหร่ที่จำเป็นต้องเปลี่ยนทุกครั้ง
ยะห์ยา

2
คุณไม่เข้าใจวิธีแก้ปัญหา myEventsQ คืออาร์เรย์ (หนึ่งใน 50 อาร์เรย์ของคุณ) ตัวอย่างข้อมูลนี้ไม่เปลี่ยนขนาดของอาร์เรย์และไม่ได้เพิ่มอาร์เรย์เพิ่มเติม แต่จะเปลี่ยนเฉพาะต้นแบบของอาร์เรย์ที่มีอยู่เท่านั้น
Sych

1
อืมฉันเห็นควรให้คำอธิบายเพิ่มเติม!
ยะห์ยา

3
pushส่งคืนlengthอาร์เรย์ ดังนั้นคุณสามารถรับค่าที่ส่งกลับ Array.prototype.push.applyไปยังตัวแปรและส่งคืนจากpushฟังก์ชันที่กำหนดเอง
adiga

12

ฉันพบสิ่งต่อไปนี้ที่ดูเหมือนจะทำได้: https://github.com/mennovanslooten/Observable-Arrays

Observable-Arrays ขยายขีดล่างและสามารถใช้ดังต่อไปนี้: (จากหน้านั้น)

// For example, take any array:
var a = ['zero', 'one', 'two', 'trhee'];

// Add a generic observer function to that array:
_.observe(a, function() {
    alert('something happened');
});

13
นี้เป็นสิ่งที่ดี แต่มีข้อแม้สำคัญ: เมื่ออาร์เรย์มีการแก้ไขเช่นarr[2] = "foo"การแจ้งเตือนการเปลี่ยนแปลงเป็นไม่ตรงกัน เนื่องจาก JS ไม่มีวิธีใดในการเฝ้าดูการเปลี่ยนแปลงดังกล่าวไลบรารีนี้จึงอาศัยการหมดเวลาที่รันทุกๆ 250 มิลลิวินาทีและตรวจสอบว่าอาร์เรย์มีการเปลี่ยนแปลงหรือไม่ดังนั้นคุณจะไม่ได้รับการแจ้งเตือนการเปลี่ยนแปลงจนกว่าจะถึงวันถัดไป เวลาหมดเวลาทำงาน อย่างไรก็ตามการเปลี่ยนแปลงอื่น ๆ เช่นpush()ได้รับการแจ้งเตือนทันที (พร้อมกัน)
peterflynn

6
นอกจากนี้ฉันเดาว่าช่วงเวลา 250 จะส่งผลต่อประสิทธิภาพไซต์ของคุณหากอาร์เรย์มีขนาดใหญ่
Tomáš Zato - คืนสถานะ Monica

ใช้เพียงแค่นี้ได้ผลเหมือนมีเสน่ห์ สำหรับเพื่อนที่ใช้โหนดของเราฉันใช้คาถานี้ด้วยคำสัญญา (รูปแบบในความคิดเห็นเป็นความเจ็บปวด ... ) _ = ต้องใช้ ('lodash'); ต้องการ ("ขีดล่างสังเกต") ( ); Promise = ต้องใช้ ("bluebird"); ส่งคืน Promise ใหม่ (ฟังก์ชัน (แก้ไขปฏิเสธ) {return _.observe (que, 'delete', function () {if ( .isEmpty (que)) ( return fix (action);}});});
Leif

7

ฉันใช้รหัสต่อไปนี้เพื่อฟังการเปลี่ยนแปลงของอาร์เรย์

/* @arr array you want to listen to
   @callback function that will be called on any change inside array
 */
function listenChangesinArray(arr,callback){
     // Add more methods here if you want to listen to them
    ['pop','push','reverse','shift','unshift','splice','sort'].forEach((m)=>{
        arr[m] = function(){
                     var res = Array.prototype[m].apply(arr, arguments);  // call normal behaviour
                     callback.apply(arr, arguments);  // finally call the callback supplied
                     return res;
                 }
    });
}

หวังว่านี่จะเป็นประโยชน์ :)


6

โหวตมากที่สุด วิธีแก้ปัญหาวิธีการกด Override ที่ได้รับการโดย @canon มีผลข้างเคียงบางอย่างที่ไม่สะดวกในกรณีของฉัน:

  • ทำให้ตัวบอกคุณสมบัติการพุชแตกต่างกัน ( writableและconfigurableควรตั้งค่าtrueแทนfalse ) ซึ่งทำให้เกิดข้อยกเว้นในภายหลัง

  • เพิ่มเหตุการณ์หลายครั้งเมื่อpush()ถูกเรียกหนึ่งครั้งโดยมีหลายอาร์กิวเมนต์ (เช่นmyArray.push("a", "b") ) ซึ่งในกรณีของฉันไม่จำเป็นและไม่ดีต่อประสิทธิภาพ

ดังนั้นนี่คือทางออกที่ดีที่สุดที่ฉันพบว่าแก้ไขปัญหาก่อนหน้านี้และอยู่ในความคิดของฉันที่สะอาดกว่า / ง่ายกว่า / เข้าใจง่ายขึ้น

Object.defineProperty(myArray, "push", {
    configurable: true,
    enumerable: false,
    writable: true, // Previous values based on Object.getOwnPropertyDescriptor(Array.prototype, "push")
    value: function (...args)
    {
        let result = Array.prototype.push.apply(this, args); // Original push() implementation based on https://github.com/vuejs/vue/blob/f2b476d4f4f685d84b4957e6c805740597945cde/src/core/observer/array.js and https://github.com/vuejs/vue/blob/daed1e73557d57df244ad8d46c9afff7208c9a2d/src/core/util/lang.js

        RaiseMyEvent();

        return result; // Original push() implementation
    }
});

โปรดดูความคิดเห็นสำหรับแหล่งที่มาของฉันและสำหรับคำแนะนำเกี่ยวกับวิธีใช้ฟังก์ชันการกลายพันธุ์อื่น ๆ นอกเหนือจาก push: 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'


@canon ฉันมี Proxies ให้ใช้ แต่ฉันไม่สามารถใช้มันได้เนื่องจากอาร์เรย์ถูกแก้ไขจากภายนอกและฉันไม่สามารถคิดวิธีใดที่จะบังคับให้ผู้โทรภายนอก (ซึ่งนอกเหนือจากการเปลี่ยนแปลงเป็นครั้งคราวโดยไม่มีการควบคุมของฉัน) เพื่อใช้ Proxy .
cprcrack

@canon และอย่างไรก็ตามความคิดเห็นของคุณทำให้ฉันตั้งสมมติฐานผิดซึ่งก็คือฉันใช้ตัวดำเนินการกระจายเมื่อฉันไม่ได้จริงๆ ไม่ฉันไม่ได้ใช้ประโยชน์จากตัวดำเนินการสเปรดเลย สิ่งที่ฉันใช้คือพารามิเตอร์ที่เหลือซึ่งมี...ไวยากรณ์ที่คล้ายกันและสามารถแทนที่ได้อย่างง่ายดายด้วยการใช้argumentsคำหลัก
cprcrack

การเชื่อมโยงเหล่านี้คือ ... : github.com/vuejs/vue/blob/... github.com/vuejs/vue/blob/...
แอนดรู

0
if (!Array.prototype.forEach)
{
    Object.defineProperty(Array.prototype, 'forEach',
    {
        enumerable: false,
        value: function(callback)
        {
            for(var index = 0; index != this.length; index++) { callback(this[index], index, this); }
        }
    });
}

if(Object.observe)
{
    Object.defineProperty(Array.prototype, 'Observe',
    {
        set: function(callback)
        {
            Object.observe(this, function(changes)
            {
                changes.forEach(function(change)
                {
                    if(change.type == 'update') { callback(); }
                });
            });
        }
    });
}
else
{
    Object.defineProperties(Array.prototype,
    { 
        onchange: { enumerable: false, writable: true, value: function() { } },
        Observe:
        {
            set: function(callback)
            {
                Object.defineProperty(this, 'onchange', { enumerable: false, writable: true, value: callback }); 
            }
        }
    });

    var names = ['push', 'pop', 'reverse', 'shift', 'unshift'];
    names.forEach(function(name)
    {
        if(!(name in Array.prototype)) { return; }
        var pointer = Array.prototype[name];
        Array.prototype[name] = function()
        {
            pointer.apply(this, arguments); 
            this.onchange();
        }
    });
}

var a = [1, 2, 3];
a.Observe = function() { console.log("Array changed!"); };
a.push(8);

1
ดูเหมือนObject.observe()และArray.observe()ถูกถอนออกจากสเป็ค การสนับสนุนถูกดึงออกจาก Chrome แล้ว : /
canon

0

ไม่แน่ใจว่าสิ่งนี้ครอบคลุมทุกอย่างหรือไม่ แต่ฉันใช้สิ่งนี้ (โดยเฉพาะอย่างยิ่งเมื่อทำการดีบั๊ก) เพื่อตรวจจับเมื่ออาร์เรย์มีการเพิ่มองค์ประกอบ:

var array = [1,2,3,4];
array = new Proxy(array, {
    set: function(target, key, value) {
        if (Number.isInteger(Number(key)) || key === 'length') {
            debugger; //or other code
        }
        target[key] = value;
        return true;
    }
});

-1

ห้องสมุดคอลเลกชันที่น่าสนใจคือhttps://github.com/mgesmundo/smart-collection ช่วยให้คุณสามารถดูอาร์เรย์และเพิ่มมุมมองให้กับอาร์เรย์ได้เช่นกัน ไม่แน่ใจเกี่ยวกับประสิทธิภาพเนื่องจากฉันกำลังทดสอบด้วยตัวเอง จะอัปเดตโพสต์นี้เร็ว ๆ นี้


-1

ฉันเล่นไปมาและคิดขึ้นมานี้ แนวคิดคืออ็อบเจ็กต์มีเมธอด Array.prototype ที่กำหนดไว้ทั้งหมด แต่รันบนอ็อบเจ็กต์อาร์เรย์แยกต่างหาก สิ่งนี้ทำให้สามารถสังเกตเมธอดเช่น shift (), pop () เป็นต้นแม้ว่าบางวิธีเช่น concat () จะไม่ส่งคืนอ็อบเจกต์ OArray การใช้วิธีการเหล่านี้มากเกินไปจะไม่ทำให้วัตถุสามารถสังเกตได้หากใช้อุปกรณ์เสริม เพื่อให้บรรลุผลในภายหลังตัวเข้าถึงถูกกำหนดสำหรับแต่ละดัชนีภายในความจุที่กำหนด

ประสิทธิภาพที่ชาญฉลาด ... OArray ช้ากว่าประมาณ 10-25 เท่าเมื่อเทียบกับวัตถุ Array ธรรมดา สำหรับความสามารถในช่วง 1 - 100 ความแตกต่างคือ 1x-3x

class OArray {
    constructor(capacity, observer) {

        var Obj = {};
        var Ref = []; // reference object to hold values and apply array methods

        if (!observer) observer = function noop() {};

        var propertyDescriptors = Object.getOwnPropertyDescriptors(Array.prototype);

        Object.keys(propertyDescriptors).forEach(function(property) {
            // the property will be binded to Obj, but applied on Ref!

            var descriptor = propertyDescriptors[property];
            var attributes = {
                configurable: descriptor.configurable,
                enumerable: descriptor.enumerable,
                writable: descriptor.writable,
                value: function() {
                    observer.call({});
                    return descriptor.value.apply(Ref, arguments);
                }
            };
            // exception to length
            if (property === 'length') {
                delete attributes.value;
                delete attributes.writable;
                attributes.get = function() {
                    return Ref.length
                };
                attributes.set = function(length) {
                    Ref.length = length;
                };
            }

            Object.defineProperty(Obj, property, attributes);
        });

        var indexerProperties = {};
        for (var k = 0; k < capacity; k++) {

            indexerProperties[k] = {
                configurable: true,
                get: (function() {
                    var _i = k;
                    return function() {
                        return Ref[_i];
                    }
                })(),
                set: (function() {
                    var _i = k;
                    return function(value) {
                        Ref[_i] = value;
                        observer.call({});
                        return true;
                    }
                })()
            };
        }
        Object.defineProperties(Obj, indexerProperties);

        return Obj;
    }
}

แม้ว่าจะทำงานกับองค์ประกอบที่มีอยู่ แต่จะไม่ทำงานเมื่อมีการเพิ่มองค์ประกอบด้วยอาร์เรย์ [new_index] = value พร็อกซีเท่านั้นที่สามารถทำได้
นาทีที่

-5

ฉันไม่แนะนำให้คุณขยายต้นแบบดั้งเดิม แต่คุณสามารถใช้ไลบรารีเช่นรายการใหม่ https://github.com/azer/new-list

สร้างอาร์เรย์ JavaScript ดั้งเดิมและให้คุณสมัครรับการเปลี่ยนแปลงใด ๆ มันรวมการอัปเดตและให้ความแตกต่างขั้นสุดท้าย

List = require('new-list')
todo = List('Buy milk', 'Take shower')

todo.pop()
todo.push('Cook Dinner')
todo.splice(0, 1, 'Buy Milk And Bread')

todo.subscribe(function(update){ // or todo.subscribe.once

  update.add
  // => { 0: 'Buy Milk And Bread', 1: 'Cook Dinner' }

  update.remove
  // => [0, 1]

})
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.