Skip to content

Instantly share code, notes, and snippets.

@alucky0707
Last active December 15, 2015 20:28
Show Gist options
  • Save alucky0707/5318509 to your computer and use it in GitHub Desktop.
Save alucky0707/5318509 to your computer and use it in GitHub Desktop.
Slice like Ruby for JavaScript
(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);
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