【保存版】js 現場で役立つスニペット集


## どんなに多次元の配列でもディープコピー（値渡し）する

```js
/**
 * @return {[type]}         [description]
 */
Array.prototype.clone = function() {
  return JSON.parse(JSON.stringify(this));
};
```

## `.map` の多次元版

```js
/**
 * INFO: 3次元以降に対応していない。したい。
 * @param  {[type]}
 * @return {[type]}
 */
Array.prototype.mapAll = function(fn) {
  return this.map((a, y)=> {
    return a.map((v, x)=> {
      return fn(v, { x:x, y:y }, this);
    });
  });
};
```

## 右回転する

```js
/**
 * 右回転する
 * INFO: 3次元以降に対応していない。したい。
 * @return {[type]} [description]
 */
Array.prototype.turn = function() {
  return this.mapAll((_, p, a)=> this[this.length-1-p.x][p.y]);
};
```

## 条件にあてはまる要素のkeyを配列にして返す

```js
// 例
var a = [ { number: 10 }, { number: 20 }, { number: 20 }, { number: 30 } ];
var b = a.reduce(function( prev, curr, index, array ) {
    if ( curr.number === 20 ) {
        prev.push( index );
    }
    return prev;
}, [] );
console.log(b);
```

## `JSON.parse` can parse `'false'`, `'1'` to `false`, `1` as well.

```js
  /**
   * @return {any} - "getAttribute" is return null when not found the attribute.
   */
  getValueByAttr(attributeName) {
    var v = document.querySelector('[data-aja-meta-search]').getAttribute(attributeName);
    // INFO: parse `'false'`, `'1'` to `false`, `1` as well.
    return JSON.parse(v);
  }
```

## ２つの配列をマージする

- コンフリクト起きた要素はcallbackが発火される
- callbackを使ってどちらの値を使うかなど選択できる

```js
/**
 * 非破壊型
 * sample: `[0,1].merge(1, [0,0]) => [0,0,0]`
 * @param  {[type]}   X   - 位置をindexで指定
 * @param  {[type]}   arr - マージしたい配列
 * @param  {Function} fn  - call when conflict.
 * @return {[type]}       [description]
 *
 * INFO: .map関数でやりたかったが値が特殊値`empty`の場合はmapのコールバックが呼ばれないorz
 */
Array.prototype.merge = function(X, arr, fn = function(val1, val2) { return val2 }) {
  var newArr = [];
  var newArrLength = Math.max(X + arr.length, this.length);
  for (var i = 0; i < newArrLength; i++) {
    var val = this[i];
    if(i<X) {
      newArr[i] = val;
    }
    else if(undefined !== this[i] && undefined !== arr[i-X]) {
      newArr[i] = fn(val, arr[i-X], i);
    }
    else {
      newArr[i] = undefined !== arr[i-X] ? arr[i-X] : this[i];
    }
  }
  return newArr;
};
```

## 縦軸と横軸入れ替える

```js
/**
 * 縦軸と横軸入れ替える
 * `左上と右下を結ぶ`軸で入れ替えるのであらゆる面で都合が良い
 * @return {[type]}
 */
Array.prototype.transpose = function() {
  return this[0].map((_, i)=> this.map(a=> a[i]));
}
```

## consoleに視認性良く表示させる

```js
/**
 * 2次元配列専用
 * @return {[type]}
 */
Array.prototype.stringify = function() {
  var str = '\n';
  this.forEach((arr)=> {
    str += JSON.stringify(arr) + "\n";
  });
  return str;
};
```

## 条件(fn)にあった場所を`{x, y}`の配列で返す

```js
/**
 * INFO: 3次元以降に対応していない。したい。
 * @param {function}
 *        @arg {any} - {探索中の値}
 *        @arg {object} - {x,y}
 * @return {Array}
 */
Array.prototype.getPositions = function(fn) {
  return this.map((a, y)=> {
    return a.map((v, x)=> {
      return fn(this[y][x], { x:x, y:y }) ? { x:x, y:y } : undefined;
    }).filter((v)=> v!==undefined);
  })
  // INFO: 2次元配列を1次元配列に
  .reduce((pre,current) => {pre.push(...current);return pre},[]);
};

// 以下も同じ

Array.prototype.getPositions = function(fn) {
  return this.reduce((prev1,curr1,y,a)=> {
    return a.reduce((prev2,curr2,x)=> {
      if (fn(this[y][x], { x:x, y:y })) {
        prev1.push({ x:x, y:y });
      }
      return prev1;
    }, []);
  }, []);
};
```

## 他にも

```coffeescript

# INFO: [4,3,4,5,4,3,2,2,4,5,3,3,3,3,5,5,3,4,4] といった配列を出現順に並び替える
# INFO: 以下では v.id となっているが これは 値が { id: 3, aId, 2, bId: 8 } のときに id で比較させているため。値が 3 であれば v だけで良い
sortByFrequency = (array) ->
	frequency = {}
	array.forEach (v) ->
		frequency[v.id] = 0
	uniques = array.filter((v) ->
		++frequency[v.id] == 1
	)
	uniques.sort (a, b) ->
		frequency[b.id] - frequency[a.id]
```

```coffeescript
Array.prototype.removeDuplicates = ()->
	Array.from(new Set(this))
```
```coffeescript
Array.prototype.serialize = ()->
	this.reduce((pre,current)->
		pre.push.apply(pre, current);
		pre
	,[])
```

## 恒久的なカウントアップ

```js
const countUp = function(key) {
  const a = [];
  a[key] = JSON.parse(localStorage.getItem(key));
  a[key] === null && a[key] = 0;
  localStorage.setItem(key, JSON.stringify(++a[key]));
  return a[key];
};
```