이 블로그는 크로뮴, Gecko 환경에서 제일 잘 작동됩니다.
profile

글루미스토어

프론트엔드 개발 블로그입니다. Nextjs 14로 개발되었습니다.

자바스크립트 배열 고차함수 직접 구현하기(map, reduce, filter, forEach, sort) 프론트엔드 코딩테스트

my Blog!

자바스크립트 배열 고차함수 직접 구현하기(map, reduce, filter, forEach, sort) 프론트엔드 코딩테스트

조회수1173<b>[운영자]</b>영이





Array.prototype.customMap = function(callback, thisArg) {
  const newArr = [];
  for (let i = 0; i < this.length; i++) {
    newArr.push(callback.bind(thisArg)(this[i], i, this));
  }
  return newArr;
};

const babo1 = [1, 2, 3, 4].customMap((elm, idx, arr) => {
  return elm * 2;
},this);

console.log(babo1)
// [2,4,6,8]


1. map

맵의 경우 새로운 배열을 반환하기 때문에 newArr을 생성해서 

조건에 따라 새로운 element를 넣어준다.







Array.prototype.customForEach = function(callback, thisArg) {
  for (let i = 0; i < this.length; i++) {
    callback.bind(thisArg)(this[i], i, this);
  }
  return undefined;
};

const babo2 = [1, 2, 3, 4].customForEach((elm, idx, arr) => {
  return elm * 2;
}, this);
console.log(babo2)
// undefined



2. forEach

forEach는 뭔가 반환하는 것보다는, 콜백함수를 실행하는것 그 자체가 목적이기 때문에

undefined를 내뱉으면 된다.








Array.prototype.customFilter = function(callback, thisArg) {
  const newArr = [];
  for (let i = 0; i < this.length; i++) {
		const elm = callback.bind(thisArg)(this[i], i, this);
    if(elm) newArr.push(this[i]);
  }
  return newArr;
};

const babo3 = [1, 2, 3, 4].customFilter((elm, idx, arr) => {
  return elm % 2 === 0
}, this);
console.log(babo3)
// [2,4]



3. filter

조건문이 truthy냐, falsy냐에 따라 배열에 넣고 안넣고가 결정된다.

때문에 굳이 undefined, null 등을 지정하지 않고,

그냥 콜백함수 return값만 넣으면 저절로 필터가 완성됨.


NaN도 알아서 잘 falsy로 적용한다.







Array.prototype.customReduce = function(callback, initialValue) {
  for (let i = 0; i < this.length; i++) {
		if(!initialValue) initialValue = this[i]
		else initialValue = callback(initialValue,this[i],i,this)
  }
  return initialValue;
};

const babo4 = [1, 2, 3, 4].customReduce((acc, elm, idx, arr) => {
  return acc + elm
});
console.log(babo4)
// 10



4. reduce

4천왕중에 얘만 this의 명시적 바인딩이 되지 않는다. (위의 다른 식들과 달리 bind, call 없음)

물론 this를 수동으로 바인딩 하는 행위는 

실제 프로그래밍을 하면서도 좀처럼 할 일이 없어서 크게 상관 없다.


아무튼 initialValue가 없으면 배열의 첫 번째 인자를 initialValue로 지정하고,

이후로는 콜백함수에서 나온 결과값을 계속 for문 돌려서 

마지막에 return 하면 된다.







Array.prototype.customSort = function(callback) {
	let sorted = false
	while(!sorted) {
		sorted = true
		for(let i=0; i < this.length-1; i++) {
			if(callback(this[i],this[i+1]) >= 0 || callback(this[i],this[i+1]) === false) {
				[this[i],this[i + 1]] = [this[i + 1],this[i]];
				sorted = false
			}
		}
	}
	return this
}
const babo5 = [5,4,1,2,3].customReduce((a,b) => {
  return a - b
});
console.log(babo5)
// [1,2,3,4,5]


5. sort()

조건에 부합하지 않으면 무한으로 while문을 돌리는 방식이다.

때문에 최악의 경우 시간 복잡도는 O(N^2) 로, 꽤 긴 편이다.


이는 최악의 경우이고, 전부 truthy로 한 방에 통과되면 

시간 복잡도는 O(N)이다.


ex) [1,2,3,4,5].sort((a,b) => a - b)

// 한바퀴만 돌고 끝나니깐 O(N)임


단, 시간복잡도라는건 가장 오래 걸리는 케이스를 기준으로 잡으므로,

O(N^2) 라고 대답하는게 정답이다.



reverse()의 경우는 그냥 elm.pop()을 새로운 배열에 계속 넣으면 되기 때문에

시간 복잡도는 O(N)이며, 구현이 매우 쉬워서 굳이 이 포스팅에는 적지 않겠다.





※ 참고로 prototype을 추가할 때 화살표 함수를 쓰면 

함수를 선언하는 그 시점에 바로 this가 결정되어버려서 

prototype에서 this를 사용하는게 불가능해짐.


그에 반해 일반 함수식은 function을 어디서 부르느냐에 따라 this가 결정되기 때문에 

동적인 this 바인딩이 가능해진다.


결론적으로, 화살표 함수는 일반함수식이나 메소드함수를 절대 대체할 수 없다는게 내 생각이다.







댓글: 0