[Underscore.js] Underscore library with ES6

_.identity = (val) => val;
_.first = (array, n) =>  n === undefined ? array[0] : array.slice(0, n)

_.last = (array, n) => n === undefined ? array[array.length - 1] : n === 0 ? [] : array.slice(-n)
_.each = (collection, iterator) => {
  if (Array.isArray(collection)) {
    for (let i = 0; i < collection.length; i++) {
    iterator(collection[i], i, collection);
    }
  } else {
    for (let prop in collection) {
      iterator(collection[prop], prop, collection);
    }
  }
};
_.indexOf = (array, target) => {
  let result = -1;

  _.each(array, (item, index) => {
    if (item === target && result === -1) {
      result = index;
    }
  });

  return result;
};
_.filter = (collection, test) => {
  let filterredArr = [];

  _.each(collection, (value, element) => {
    if (test(value)) filterredArr.push(value);
  });

  return filterredArr;
};

_.reject = (collection, test) => (_.filter(collection, x => !test(x)))
_.uniq = (array) => {
  let uniqueArr = [];
  array = array.sort();

  for (let i = 0; i < array.length; i++) {
    if (array[i] !== array[i+1]) uniqueArr.push(array[i]);
  }

  return uniqueArr;
};
_.map = (collection, iterator) => {
  let mappedArr = [];

  _.each(collection, (value) => mappedArr.push(iterator(value)));

  return mappedArr;
};

_.pluck = (collection, key) => _.map(collection, (item) => item[key])
_.reduce = (collection, iterator, accumulator) => {
  let isFirst = true;

  _.each(collection,(item,idx,arr)=>{
    if(accumulator===undefined&&isFirst){
      accumulator = item;
      isFirst = false;
    } else {
      accumulator=iterator(accumulator,item,idx,arr)
    }
  })

  return accumulator;
};
_.contains = (collection, target) => _.reduce(collection, (wasFound, item)=> wasFound ? true : item === target ,false)
_.every = (collection, iterator) =>
  _.reduce(collection, (isEvery, item) => {
    iterator = iterator || _.identity;
    return (!iterator(item)) ? false : isEvery;
  }, true)

_.some = (collection, iterator) =>
  _.reduce(collection, (isSome, item) => {
    iterator = iterator || _.identity;
    return (iterator(item)) ? true : isSome;
  }, false)
_.extend = function(obj, ...arg) {
  let extendedObj = obj;

  for( let i = 0 ; i < arg.length ; i++){
    for( let prop in arg[i]){
      extendedObj[prop] = arg[i][prop]
    }
  }
	return extendedObj;
}

_.defaults = function(obj, ...arg) {
  let defaultObj = obj;

  for (let i = 1; i < arg.length; i++) {
    for (let prop in arguments[i]) {
      if (defaultObj[prop] === undefined) defaultObj[prop] = arguments[i][prop];
    }
  }

  return defaultObj;
};
_.once = function(func) {
  var alreadyCalled = false;
  var result;

  return function() {
    if (!alreadyCalled) {
      result = func.apply(this, arguments);
      alreadyCalled = true;
    }
    return result;
  };
};
_.memoize = (func) => {
  let cache = {};

  return function(...arg) {
    if (!cache.hasOwnProperty(JSON.stringify(arg))) {
      cache[JSON.stringify(arg)] = func.apply(null, arg);
    }
    return cache[JSON.stringify(args)]
  }
};
_.delay = (...args) => {
  setTimeout.apply(null, args);
};
_.shuffle = (array) => {
  let shuffledArr = [];
  let randomIndex = Math.round(Math.random() * (array.length) + 1);

  for (let i = 0; i < array.length; i++) {
    shuffledArr.splice(randomIndex, 0, array[i]);
  }

  return shuffledArr;
};
_.invoke = (collection, functionOrKey, args) => {
  if (typeof functionOrKey === 'function') {
    return _.map(collection, (element) => functionOrKey.call(element))
  } else if (typeof collection[0] === 'string') {
    return _.map(collection, (element) => String.prototype[functionOrKey].call(element))
  }
};
_.sortBy = function(collection, iterator) {
  let temp;

  if (typeof iterator !== 'function') {
    if (typeof String.prototype[iterator] === 'function') {
      iterator = String.prototype[iterator].call(x);
    } else {
      iterator = (x) => x.length;
    }
  }

  for (let i = 0; i < collection.length; i++) {
    for (let j = i + 1; j < collection.length; j++) {
      if (String(iterator(collection[i])) > String(iterator(collection[j]))) {
        temp = collection[i];
        collection[i] = collection[j]
        collection[j] = temp
      }
    }
  }
  return collection
};
_.zip = function(...arg) {
  let temp = _.map(arg,(item)=> item.length)
  const maxLength = Math.max.apply(null, temp);

  let zippedArr = [];
  for (var i = 0; i < maxLength; i++) {
    var innerArr = [];
    for (var j = 0; j < arguments.length; j++) {
      innerArr.push(arguments[j][i]);
    }
    zippedArr.push(innerArr);
  }

  return zippedArr;
};
_.flatten = (nestedArray, result) => {
  result = result || [];

  for (var i = 0; i < nestedArray.length; i++) {
    if (Array.isArray(nestedArray[i])) {
      _.flatten(nestedArray[i], result);
    } else {
      result.push(nestedArray[i])
    }
  }

  return result;
};
_.intersection = function(...arg) {
	let allElem = _.uniq(_.flatten(arg))

	return _.filter(allElem, (everyElem) => (_.every(arg, (argElem) => argElem.includes(everyItem))))
};

_.difference = function(array) {
  let arg = Array.prototype.slice.call(arguments,1)

  return _.filter(arguments[0],function(elem) {
    return !_.some(arg, function(argElem) {
      return argElem.includes(elem)
    })
  })
};
_.throttle = (func, wait) => {
	var used = true;    // 함수가 호출될 때마다 계속 실행되는 것을 제한하는 Flag

	return () => {
		if (!used) {      // used가 false라면, 즉 함수가 실행된 적이 없다면, callback 함수를 실행
			func();
			used = true;    // callback 함수를 다시 실행할 수 없도록 제한하는 역할
		}
		setTimeout(() => {
			used = false;    // 일정시간이 경과하면 callback 함수를 다시 실행 가능하도록 조건을 변경
		}, wait);
	}
};


© 2018. by Jae