admin管理员组

文章数量:1292177

I'm learning about observing Array objects. I found the following surprising:

var fooArray = [];
Array.observe(fooArray, function(changes){
    console.log('changes:', changes[0].type);
});
fooArray.push({});

results in the type of change being splice and not add

What methods would result in a change event of type add? It would seem to me that pushing a single value on it would be the most likely scenario.

I'm learning about observing Array objects. I found the following surprising:

var fooArray = [];
Array.observe(fooArray, function(changes){
    console.log('changes:', changes[0].type);
});
fooArray.push({});

results in the type of change being splice and not add

What methods would result in a change event of type add? It would seem to me that pushing a single value on it would be the most likely scenario.

Share asked Mar 26, 2015 at 0:30 Sean AndersonSean Anderson 29.4k33 gold badges132 silver badges242 bronze badges 5
  • 1 Changing properties, at least. Adding to the collection is technically splicing, whether you're adding or removing. If you tried fooArray.f = "whatever";, you'd see it be for "add" – Ian Commented Mar 26, 2015 at 0:35
  • The MDN documentation states "Index assignment changes which do not change the length of the array may be reported as update changes" Would that not fall under an update and not an add? Or only if 'f' does not exist yet? – Sean Anderson Commented Mar 26, 2015 at 0:38
  • Why do you bring that up? Setting properties isn't the same as index assignment – Ian Commented Mar 26, 2015 at 0:39
  • I see now. It does make some sense, but I guess a bit unintuitive to those uninformed. Feel free to submit it as an answer. – Sean Anderson Commented Mar 26, 2015 at 0:40
  • Well, I was lucky to guess and see that setting properties would trigger the "add" event. I hadn't known, and I'm not sure if it's the only way, so I was hoping for someone else to chime in – Ian Commented Mar 26, 2015 at 0:44
Add a ment  | 

3 Answers 3

Reset to default 7

The MDN reference is not clear about what circumstances fire each change type. Here is a detailed explanation:

splice

Covers every change that you would expect to happen in an array. All the following functions trigger it:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()

update

Triggers if the value of some element changes:

var arr = ['a', 'b', 'c'];
Array.observe(arr, function (changes) {
    console.dir(changes);
});
arr[0] = 'A'; // triggers 'update'

It's worth mentioning that some array functions may also trigger it, like reverse().

add | delete

As unintuitive as it seems, these types are triggered when a property is added to/deleted from the array. For example:

var arr = ['a', 'b', 'c'];
Array.observe(arr, function (changes) {
    console.dir(changes);
});
arr.foo = 'bar'; // triggers 'add'
delete arr.foo;  // triggers 'delete'

P.S.: See Jack's answer on why it behaves like this.

The change observer is actually implemented in Object, from which Array inherits. You can get your expected behaviour when you use Object.observe() instead:

var arr = [];
Object.observe(arr, function(changes) {
  console.log(changes)
});
arr.push({});

Output:

[
    {"type":"add","object":[{}],"name":"0"},
    {"type":"update","object":[{}],"name":"length","oldValue":0}
]

As you can see, two things happen here:

  1. An object is added under property 0 (i.e. first element),
  2. The length property is updated to reflect the new number of elements.

The Array.observe() groups those two changes together into a single splice change; basically, anything that affects the length of an array will fall under this. The add and delete change types will only be triggered for normal properties, leaving just the update change type to work in the same way.

By adjusting the accept type list of Object.observe() via the optional third argument, you can confirm this:

var arr = [];
Object.observe(arr, function(changes) {
  console.log(changes)
}, ['add', 'update', 'delete', 'splice']);
arr.push({});

Output:

[
    {"type":"splice","object":[{}],"index":0,"removed":[],"addedCount":1}
]

In fact, Array.observe() can be implemented like this:

Array.observe = function(arr, callback) {
    return Object.observe(arr, callback, ["add", "update", "delete", "splice"]);
};

As such, the following change types aren't sent to your callback when you use Array.observe():

["reconfigure", "setPrototype", "preventExtensions"]

In addition to setting custom properties such as arr.b = 1 it is also possible, at least currently using V8 in Node, Opera or Chrome, to trigger "add" changes on Array using:

arr = []
arr[1] = 1 // "splice" change
arr[0] = 1 // "add" change

本文标签: javascriptUnder what condition would Arrayobserve39s quotaddquot event triggerStack Overflow