index.js 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. function klona(x) {
  2. if (typeof x !== 'object') return x;
  3. var k, tmp, str=Object.prototype.toString.call(x);
  4. if (str === '[object Object]') {
  5. if (x.constructor !== Object && typeof x.constructor === 'function') {
  6. tmp = new x.constructor();
  7. for (k in x) {
  8. if (x.hasOwnProperty(k) && tmp[k] !== x[k]) {
  9. tmp[k] = klona(x[k]);
  10. }
  11. }
  12. } else {
  13. tmp = {}; // null
  14. for (k in x) {
  15. if (k === '__proto__') {
  16. Object.defineProperty(tmp, k, {
  17. value: klona(x[k]),
  18. configurable: true,
  19. enumerable: true,
  20. writable: true,
  21. });
  22. } else {
  23. tmp[k] = klona(x[k]);
  24. }
  25. }
  26. }
  27. return tmp;
  28. }
  29. if (str === '[object Array]') {
  30. k = x.length;
  31. for (tmp=Array(k); k--;) {
  32. tmp[k] = klona(x[k]);
  33. }
  34. return tmp;
  35. }
  36. if (str === '[object Set]') {
  37. tmp = new Set;
  38. x.forEach(function (val) {
  39. tmp.add(klona(val));
  40. });
  41. return tmp;
  42. }
  43. if (str === '[object Map]') {
  44. tmp = new Map;
  45. x.forEach(function (val, key) {
  46. tmp.set(klona(key), klona(val));
  47. });
  48. return tmp;
  49. }
  50. if (str === '[object Date]') {
  51. return new Date(+x);
  52. }
  53. if (str === '[object RegExp]') {
  54. tmp = new RegExp(x.source, x.flags);
  55. tmp.lastIndex = x.lastIndex;
  56. return tmp;
  57. }
  58. if (str === '[object DataView]') {
  59. return new x.constructor( klona(x.buffer) );
  60. }
  61. if (str === '[object ArrayBuffer]') {
  62. return x.slice(0);
  63. }
  64. // ArrayBuffer.isView(x)
  65. // ~> `new` bcuz `Buffer.slice` => ref
  66. if (str.slice(-6) === 'Array]') {
  67. return new x.constructor(x);
  68. }
  69. return x;
  70. }
  71. exports.klona = klona;