Last active
August 29, 2015 14:22
-
-
Save Fordi/d7d741b655474e057fd5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ImmutableArray - exactly what it sounds like: an Array you can't change. | |
* | |
* Usage: | |
* var myArray = [1, 2, 3], | |
* myImmutableArray = myArray.immutable; | |
* | |
* ImmutableArrays can be used in place of normal Arrays in most cases, with the exception of the following mutator functions: | |
* #pop(), #push(item), #reverse(), #shift(), #unshift(item), #splice(start, length, items...), and #sort([sortfn]) | |
* If used, these will throw a warning, copy the array, mutate it, and return the mutated array. | |
*/ | |
(function () { | |
"use strict"; | |
/** | |
* @private | |
* Create a PropertyDescriptor for Object.defineProperty / Object.defineProperties that describes a property that cannot be changed. | |
*/ | |
function fixedProp(value) { | |
return { | |
enumerable: false, | |
configurable: false, | |
writable: false, | |
value: value | |
}; | |
} | |
/** | |
* @private | |
* Create a PropertyDescriptor for Object.defineProperty / Object.defineProperties that describes a permanent getter | |
*/ | |
function getter(get) { | |
return { | |
enumerable: false, | |
configurable: false, | |
get: get | |
} | |
} | |
/** | |
* @private | |
* The list of methods on Array.prototype that are known to mutate the array | |
*/ | |
var mutators = ["pop", "push", "reverse", "shift", "unshift", "splice", "sort"], | |
/** | |
* @private | |
* Building the extension to ImmutableArray that will override mutator functions with copier functions, and emit a warning | |
*/ | |
immutableProto = mutators.reduce(function (proto, methodName) { | |
proto[methodName] = fixedProp(function () { | |
console.warn("[Code Quality]: Calling ImmutableArray#" + methodName + "() doesn't change it; please use #mutate(callback, context), or #slice() it first. Returning the mutated copy of the array instead of the normal return value."); | |
var copy = this.slice(); | |
copy[methodName].apply(copy, arguments); | |
return copy; | |
}); | |
return proto; | |
}, {}); | |
Object.defineProperties(Array.prototype, { | |
/** | |
* Returns a new immutable Array based on this Array. | |
*/ | |
immutable: getter(function () { | |
return new ImmutableArray(this); | |
}), | |
/** | |
* Provided to create the same idempotent interface on Arrays and ImmutableArrays. Since Arrays are mutable, this returns identity | |
*/ | |
mutable: getter(function () { | |
return this; | |
}), | |
/** | |
* Get a copy of the Array; an alias for this.slice(). | |
*/ | |
copy: getter(function () { | |
return this.slice(); | |
}), | |
/** | |
* Create a new ImmutableArray from a mutation of an existing Array or ImmutableArray | |
* @param Function callback(mutableArray) The developer-supplied method used to mutate the array | |
* @param Object context The context in which to mutate the array | |
*/ | |
mutate: fixedProp(function (callback, context) { | |
var mutableArray = this.slice(); | |
callback.call(context || null, mutableArray); | |
return mutableArray.immutable; | |
}) | |
}); | |
/** | |
* @private | |
* @constructor | |
* Creates an ImmutableArray | |
* @param Array content Defines the content for the ImmutableArray | |
*/ | |
function ImmutableArray(content) { | |
this.length = content.length; | |
for (let i = 0; i < content.length; i += 1) { | |
this[i] = content[i]; | |
} | |
Object.defineProperty(this, 'constructor', fixedProp(ImmutableArray)); | |
Object.preventExtensions(this); | |
Object.freeze(this); | |
} | |
ImmutableArray.prototype = []; | |
Object.defineProperties(ImmutableArray.prototype, immutableProto); | |
Object.defineProperties(ImmutableArray.prototype, { | |
/** | |
* Provided to create the same idempotent interface on Arrays and ImmutableArrays. | |
* Since ImmutableArrays are immutable, this returns identity | |
*/ | |
immutable: getter(function () { | |
return this; | |
}), | |
/** | |
* Create a mutable copy of this ImmutableArray | |
*/ | |
mutable: getter(function () { | |
return this.slice(); | |
}), | |
/** | |
* Get a "copy" of this ImmutableArray. Since ImmutableArrays are immutable, this can be identity. | |
*/ | |
copy: getter(function () { | |
return this; | |
}) | |
}); | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment