Skip to content

Commit

Permalink
fix(ArrayObservation): ensure patch applied only once
Browse files Browse the repository at this point in the history
  • Loading branch information
bigopon committed Aug 1, 2018
1 parent 6e2ac93 commit 72b5d6d
Showing 1 changed file with 105 additions and 99 deletions.
204 changes: 105 additions & 99 deletions src/array-observation.js
Original file line number Diff line number Diff line change
@@ -1,109 +1,115 @@
/* eslint-disable no-extend-native */
import {ModifyCollectionObserver} from './collection-observation';

let pop = Array.prototype.pop;
let push = Array.prototype.push;
let reverse = Array.prototype.reverse;
let shift = Array.prototype.shift;
let sort = Array.prototype.sort;
let splice = Array.prototype.splice;
let unshift = Array.prototype.unshift;
const arrayProto = Array.prototype;
const pop = arrayProto.pop;
const push = arrayProto.push;
const reverse = arrayProto.reverse;
const shift = arrayProto.shift;
const sort = arrayProto.sort;
const splice = arrayProto.splice;
const unshift = arrayProto.unshift;
const arrayObserverKey = '__array_observer__';
const patchedKey = '__au_patched__';

Array.prototype.pop = function() {
let notEmpty = this.length > 0;
let methodCallResult = pop.apply(this, arguments);
if (notEmpty && this.__array_observer__ !== undefined) {
this.__array_observer__.addChangeRecord({
type: 'delete',
object: this,
name: this.length,
oldValue: methodCallResult
});
}
return methodCallResult;
};
if (!arrayProto[patchedKey]) {
arrayProto[patchedKey] = 1;
arrayProto.pop = function() {
let notEmpty = this.length > 0;
let methodCallResult = pop.apply(this, arguments);
if (notEmpty && this[arrayObserverKey] !== undefined) {
this[arrayObserverKey].addChangeRecord({
type: 'delete',
object: this,
name: this.length,
oldValue: methodCallResult
});
}
return methodCallResult;
};

Array.prototype.push = function() {
let methodCallResult = push.apply(this, arguments);
if (this.__array_observer__ !== undefined) {
this.__array_observer__.addChangeRecord({
type: 'splice',
object: this,
index: this.length - arguments.length,
removed: [],
addedCount: arguments.length
});
}
return methodCallResult;
};
arrayProto.push = function() {
let methodCallResult = push.apply(this, arguments);
if (this[arrayObserverKey] !== undefined) {
this[arrayObserverKey].addChangeRecord({
type: 'splice',
object: this,
index: this.length - arguments.length,
removed: [],
addedCount: arguments.length
});
}
return methodCallResult;
};

Array.prototype.reverse = function() {
let oldArray;
if (this.__array_observer__ !== undefined) {
this.__array_observer__.flushChangeRecords();
oldArray = this.slice();
}
let methodCallResult = reverse.apply(this, arguments);
if (this.__array_observer__ !== undefined) {
this.__array_observer__.reset(oldArray);
}
return methodCallResult;
};
arrayProto.reverse = function() {
let oldArray;
if (this[arrayObserverKey] !== undefined) {
this[arrayObserverKey].flushChangeRecords();
oldArray = this.slice();
}
let methodCallResult = reverse.apply(this, arguments);
if (this[arrayObserverKey] !== undefined) {
this[arrayObserverKey].reset(oldArray);
}
return methodCallResult;
};

Array.prototype.shift = function() {
let notEmpty = this.length > 0;
let methodCallResult = shift.apply(this, arguments);
if (notEmpty && this.__array_observer__ !== undefined) {
this.__array_observer__.addChangeRecord({
type: 'delete',
object: this,
name: 0,
oldValue: methodCallResult
});
}
return methodCallResult;
};
arrayProto.shift = function() {
let notEmpty = this.length > 0;
let methodCallResult = shift.apply(this, arguments);
if (notEmpty && this[arrayObserverKey] !== undefined) {
this[arrayObserverKey].addChangeRecord({
type: 'delete',
object: this,
name: 0,
oldValue: methodCallResult
});
}
return methodCallResult;
};

Array.prototype.sort = function() {
let oldArray;
if (this.__array_observer__ !== undefined) {
this.__array_observer__.flushChangeRecords();
oldArray = this.slice();
}
let methodCallResult = sort.apply(this, arguments);
if (this.__array_observer__ !== undefined) {
this.__array_observer__.reset(oldArray);
}
return methodCallResult;
};
arrayProto.sort = function() {
let oldArray;
if (this[arrayObserverKey] !== undefined) {
this[arrayObserverKey].flushChangeRecords();
oldArray = this.slice();
}
let methodCallResult = sort.apply(this, arguments);
if (this[arrayObserverKey] !== undefined) {
this[arrayObserverKey].reset(oldArray);
}
return methodCallResult;
};

Array.prototype.splice = function() {
let methodCallResult = splice.apply(this, arguments);
if (this.__array_observer__ !== undefined) {
this.__array_observer__.addChangeRecord({
type: 'splice',
object: this,
index: +arguments[0],
removed: methodCallResult,
addedCount: arguments.length > 2 ? arguments.length - 2 : 0
});
}
return methodCallResult;
};
arrayProto.splice = function() {
let methodCallResult = splice.apply(this, arguments);
if (this[arrayObserverKey] !== undefined) {
this[arrayObserverKey].addChangeRecord({
type: 'splice',
object: this,
index: +arguments[0],
removed: methodCallResult,
addedCount: arguments.length > 2 ? arguments.length - 2 : 0
});
}
return methodCallResult;
};

Array.prototype.unshift = function() {
let methodCallResult = unshift.apply(this, arguments);
if (this.__array_observer__ !== undefined) {
this.__array_observer__.addChangeRecord({
type: 'splice',
object: this,
index: 0,
removed: [],
addedCount: arguments.length
});
}
return methodCallResult;
};
arrayProto.unshift = function() {
let methodCallResult = unshift.apply(this, arguments);
if (this[arrayObserverKey] !== undefined) {
this[arrayObserverKey].addChangeRecord({
type: 'splice',
object: this,
index: 0,
removed: [],
addedCount: arguments.length
});
}
return methodCallResult;
};
}

export function getArrayObserver(taskQueue, array) {
return ModifyArrayObserver.for(taskQueue, array);
Expand All @@ -121,13 +127,13 @@ class ModifyArrayObserver extends ModifyCollectionObserver {
* @returns ModifyArrayObserver always the same instance for any given array instance
*/
static for(taskQueue, array) {
if (!('__array_observer__' in array)) {
Reflect.defineProperty(array, '__array_observer__', {
if (!(arrayObserverKey in array)) {
Reflect.defineProperty(array, arrayObserverKey, {
value: ModifyArrayObserver.create(taskQueue, array),
enumerable: false, configurable: false
});
}
return array.__array_observer__;
return array[arrayObserverKey];
}

static create(taskQueue, array) {
Expand Down

0 comments on commit 72b5d6d

Please sign in to comment.