-
Notifications
You must be signed in to change notification settings - Fork 0
/
IArray.js
146 lines (125 loc) · 3.41 KB
/
IArray.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* global define */
/*
This Universal Module Definition (UMD) handles AMD, CommonJS, and Eki module loaders.
If none of those is detected, it defines IArray on the global context.
*/
(function(global, factory) {
if(typeof define === "function" && define.amd)
define(factory)
else if(typeof eki === "object" && eki.def)
eki.def("IArray", factory)
else if(typeof exports === "object")
module.exports = factory()
else
global.IArray = factory()
}(this, function() {
"use strict"
// These methods work fine as they are in Array and are non-destructive,
// but they return an array, so just call the native method and upgrade
// the returned array to an IArray
var passAndReturn = ["filter", "map", "slice"]
.reduce(function(p, c) {
p[c] = function() {
return IArray(Array.prototype[c].apply(this, arguments))
}
return p
}, {})
function concat()
{
var a2 = this.toArray() // first, clone ourselve to a standard Array
for(var argi = 0;argi < arguments.length;argi++)
{
var arg = arguments[argi]
if(arg && arg.isIArray)
a2 = a2.concat(arg.toArray())
else
a2 = a2.concat(arg)
}
return IArray(a2)
}
// These methods are mutating, so first copy the array, then
// operate on the copy, then return a new IA2
var copyAndOperate = [ "copyWithin", "fill", "push", "pop", "reverse", "shift",
"unshift", "sort", "splice"].reduce(function(p, c) {
p[c] = function() {
// create a mutable IArray object "clone" of this
var a2 = createIArray(this),
// perform the operation on it
ret = Array.prototype[c].apply(a2, arguments)
// if the returned value is a native array, convert to IArray
if(Array.isArray(ret))
ret = IArray(ret)
// store the return value
a2.ret = ret // place the return value here
// Finally, freeze it and return
return deepFreeze(a2)
}
return p
}, {})
function set(index, value)
{
var a2 = createIArray(this)
a2[index] = value
return deepFreeze(a2)
}
function rmAt(index)
{
var a2 = createIArray(this),
ret = Array.prototype.splice.call(a2, index, 1)
a2.ret = ret[0]
return deepFreeze(a2)
}
function rm(value)
{
var index = this.indexOf(value)
if(index >= 0)
return this.rmAt(index)
var a2 = createIArray(this)
a2.ret = undefined
return deepFreeze(a2) // return a clone
}
// Create our custom IArray prototype, with Array.prototype at the base
var IAProto = Object.assign(
Object.create(Array.prototype),
passAndReturn,
copyAndOperate,
{
concat: concat,
isIArray: true,
set: set,
rm: rm,
rmAt: rmAt,
toJSON: function() { return this.toArray() },
toArray: function() { return Array.prototype.slice.call(this) }
}
)
function deepFreeze(o)
{
if(IArray.freeze === "SHALLOW" || IArray.freeze === "DEEP")
{
Object.freeze(o)
if(IArray.freeze === "DEEP")
Object.getOwnPropertyNames(o)
.forEach(function(n) {
if((typeof o[n] === "object" || typeof o[n] === "function") && !Object.isFrozen(o[n]))
deepFreeze(o[n])
})
}
return o
}
// Create hte IArray object. fromArray may be a native Array
// or an IArray
function createIArray(fromArray)
{
return Object.assign(
Object.create(IAProto),
fromArray,
fromArray ? { length: fromArray.length } : null
)
}
function IArray(fromArray)
{
return deepFreeze(createIArray(fromArray))
}
return IArray
}))