Implement array.filter() by hand

rendezvous with cassidoo #125

by Jesse Rogers

HTML

<div class="wrap">
  <div id="container"></div>
  <div class="button-container">
    <button id="filter-even">
      Filter Even
    </button>
    <button id="filter-odd">
      Filter Odd
    </button>
    <button id="filter-reset">
      Reset
    </button>
  </div>
</div>

CSS

* {
  box-sizing: border-box;
  font-family: sans-serif;
}

html,
body {
  font-size: 18px;
  margin: 0;
  padding: 0;
}

#container {
  display: flex;
  flex-wrap: wrap;
  padding: 0.5rem;
  padding: calc(0.5rem - 1px);
  width: 100%;
}

.item {
  align-items: center;
  background: #212121;
  border: 1px solid white;
  color: white;
  display: flex;
  flex: 10rem;
  font-weight: bold;
  height: 10rem;
  justify-content: center;
}

.button-container {
  padding: 0.5rem;
}

button {
  background: #ffeb3b;
  border: none;
  border-radius: 0;
  color: #212121;
  cursor: pointer;
  display: inline-block;
  font-weight: bold;
  margin-right: 0.5em;
  padding: 0.5em 1em;
  -webkit-appearance: none;
}

JavaScript

// rendezvous with cassidoo #125
// implement array.filter() by hand

Array.prototype._filter = function(callback, context) {
  // error check
  if (!callback || (typeof callback).toLowerCase() !== 'function') {
    throw new TypeError('Array _filter callback must be a function!');
  }
  // allocate resultant array
  const filtered = [];

  for (let i = 0; i < this.length; i++) {
    // run callback with 'this' context if supplied
    if (context) {
      if (callback.call(context, this[i], i, this)) {
        filtered.push(this[i]);
      }
    } else {
      if (callback(this[i], i, this)) {
        filtered.push(this[i]);
      }
    }
  }

  return filtered;
}

const source = [1, 2, 3, 4, 5, 6, 7];
const container = document.getElementById('container');

// copy of source 'data' for filtering
let data = [...source];

function render() {
  // reset container before rendering
  container.innerHTML = '';
  for (let i = 0; i < data.length; i++) {
    const el = document.createElement('div');
    el.className = 'item';
    el.innerHTML = `<span>${data[i]}</span>`;
    container.append(el);
  }
}

function filter(condition) {
  // reset every time before filtering
  data = [...source];
  switch (condition) {
    case 'even':
      data = source._filter(item => item % 2 === 0);
      render();
      break;
    case 'odd':
      data = source._filter(item => item & 2 !== 0);
      render();
      break;
    default:
      render();
  }
}

// set up click listeners
const filterEvenBtn = document.getElementById('filter-even');
const filterOddBtn = document.getElementById('filter-odd');
const filterResetBtn = document.getElementById('filter-reset');

filterEvenBtn.addEventListener('click', () => filter('even'));
filterOddBtn.addEventListener('click', () => filter('odd'));
filterResetBtn.addEventListener('click', () => filter());

// initial render
render();