Last active
December 15, 2015 20:28
-
-
Save alucky0707/5318509 to your computer and use it in GitHub Desktop.
Slice like Ruby for JavaScript
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
(function(exports) { | |
"use strict"; | |
/** | |
* arr["1..3"]かarr["1,2,3"]という形式かを判断する | |
* @private | |
*/ | |
function sliceInfo(str) { | |
var | |
//arr["1..3"]という形式 | |
m = str.match(/^([+-]?\d+)\.\.([+-]?\d+)$/); | |
if (m !== null) { | |
return { | |
type: "range", | |
indexes: [parseInt(m[1],10),parseInt(m[2],10)], | |
}; | |
} | |
//arr["1,2,3"]という形式 | |
m = str.split(","); | |
if (m.length > 1) { | |
return { | |
type: "multi", | |
indexes: m | |
}; | |
} | |
//どれでもなかった | |
return null; | |
} | |
/** | |
* getハンドラの実体 | |
* @private | |
*/ | |
function get(arr,str) { | |
var | |
info = sliceInfo(str); | |
if (!info) { | |
/* //Arrayのメソッドの場合は正しく呼び出せるようbind | |
return typeof arr[str] === "function" && isNaN(parseInt(str)) ? arr[str].bind(arr) : arr[str]; | |
*/ | |
//なんか大丈夫っぽい | |
//TODO: 何で大丈夫になったのか考える | |
return arr[str]; | |
} | |
switch (info.type) { | |
case "range": | |
return arr.slice(info.indexes[0],info.indexes[1]+1); | |
case "multi": | |
return info.indexes.map(function(i) { | |
return arr[i]; | |
}); | |
} | |
} | |
/** | |
* setハンドラの実体 | |
* @private | |
*/ | |
function set(arr,str,val) { | |
var | |
//valがプリミティブ値かどうか | |
isprim = typeof val !== "object" && val === null, | |
a,b, | |
info = sliceInfo(str); | |
if (!info) { | |
arr[str] = val; | |
} else { | |
switch (info.type) { | |
case "range": | |
a = info.indexes[0]; | |
a = a < 0 ? arr.length - a : a; | |
b = info.indexes[1]; | |
b = (b < 0 ? arr.length - b : b) - a + 1; | |
arr.splice.apply(arr,[a,b].concat(val)); | |
break; | |
case "multi": | |
if (isprim) { | |
info.indexes.forEach(function(i) { | |
arr[i] = val; | |
}); | |
} else { | |
info.indexes.forEach(function(i,j) { | |
arr[i] = val[j]; | |
}); | |
} | |
break; | |
} | |
} | |
} | |
/** | |
* hasハンドラの実体 | |
* @private | |
*/ | |
function has(arr,str) { | |
var | |
info = sliceInfo(str), | |
a,b; | |
switch (info && info.type) { | |
case null: | |
return str in arr; | |
case "range": | |
a = info.indexes[0]; | |
a = a < 0 ? arr.length - a : a; | |
b = info.indexes[0]; | |
b = b < 0 ? arr.length - b : b; | |
return a < arr.length && b <= arr.length; | |
case "multi": | |
return info.indexes.every(function(i) { | |
return i in arr; | |
}); | |
} | |
} | |
/** | |
* deleteハンドラの実体 | |
* @private | |
*/ | |
function delete_(arr,str) { | |
var | |
info = sliceInfo(str), | |
a,b,i; | |
switch (info && info.type) { | |
case null: | |
return delete arr[str]; | |
case "range": | |
a = info.indexes[0]; | |
a = a < 0 ? arr.length - a : a; | |
b = info.indexes[1]; | |
b = b < 0 ? arr.length - b : b; | |
for (i = a;i <= b;i++) { | |
delete arr[i]; | |
} | |
break; | |
case "multi": | |
info.indexes.forEach(function(i) { | |
delete arr[i]; | |
}); | |
break; | |
} | |
return true; | |
} | |
/** | |
* スライス操作できるように配列を拡張する | |
* @param arr {Array} 拡張する配列 | |
* @return {Slicer} | |
*/ | |
function toSlicer(arr) { | |
var | |
handler = createHandler(arr); | |
return Proxy.create(handler); | |
} | |
/** | |
* @private | |
*/ | |
function createHandler(arr) { | |
return { | |
//arr[name] | |
get: function(_,name) { | |
return get(arr,name); | |
}, | |
//arr[name] = val | |
set: function(_,name,val) { | |
set(arr,name,val); | |
}, | |
//name in arr | |
has: function(name) { | |
return has(arr,name); | |
}, | |
hasOwn: function(name) { | |
return Object.prototype.hasOwnProperty(arr,name); | |
}, | |
// delete arr[name]; | |
delete: function(name) { | |
return delete_(arr,name); | |
}, | |
getPropertyDescripter: function(name) { | |
return Object.getPropertyDescripter(arr,name); | |
}, | |
getOwnPropertyDescripter: function(name) { | |
return Object.getOwnPropertyDescripter(arr,name); | |
}, | |
getOwnPropertyNames: function() { | |
return Object.getOwnPropertyNames(arr); | |
}, | |
getPropertyNames: function() { | |
return Object.getPropertyNames(arr); | |
}, | |
fix: function() { | |
if(Object.isFrozen(arr)) { | |
return Object.getOwnPropertyNames(arr).map(function(name) { | |
return Object.getOwnPropertyDescriptor(arr, name); | |
}); | |
} | |
return undefined; | |
}, | |
enumerate: function() { | |
var res = []; | |
for (var name in arr) { | |
res.push(name); | |
} | |
return res; | |
}, | |
keys: function() { | |
return Object.keys(arr); | |
}, | |
}; | |
} | |
//export | |
exports.toSlicer = toSlicer; | |
})(typeof this.exports !== "undefined" ? this.exports : this); |
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
var | |
arr = [1,2,3,4,5], | |
sli = toSlicer(arr); | |
console.log(sli["1..3"]); // 2,3,4 | |
console.log(sli["0,2,4"]); // 1,3,5 | |
sli["1..3"] = [6,7,8]; | |
sli["2,4"] = sli["4,2"]; | |
sli.push(9); | |
console.log(sli); // 1,6,5,8,7,9 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment