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 바인딩이 가능해진다.
결론적으로, 화살표 함수는 일반함수식이나 메소드함수를 절대 대체할 수 없다는게 내 생각이다.
댓글: 1