[과제] Underbar
Bare Minimum Requirement
- 이번 스프린트에서 사용 가능한 내장 메소드 : Array.prototype의 'pop', 'push', 'shift', 'sort' 로 한정됨. 다른 메소드 사용 금지!
- 단 새로운 함수 구현시 이전에 구현함 함수 활용 가능
identity
- _.identity는 전달인자가 무엇이든 그대로 리턴
- 이 함수는 underbar의 기능 구현 및 테스트를 위해 재사용되는 함수
_.identity = function (val) {
return val;
};
slice
- _.slice는 배열의 start 인덱스 부터 end 인덱스 이전 까지의 요소를 shallow copy하여 새로운 배열 리턴
_.slice = function (arr, start, end) {
let _start = start || 0, // `start`가 undefined인 경우, slice는 0부터 동작
_end = end;
// 입력받은 인덱스가 음수일 경우, 마지막 인덱스부터 매칭
if (start < 0)
_start = Math.max(0, arr.length + start);
// 입력받은 인덱스는 0 이상이어야 함
if (end < 0)
_end = Math.max(0, arr.length + end);
// `end`가 생략될 경우(undefined), slice는 마지막 인덱스까지 동작
// `end`가 배열의 범위를 벗어날 경우, slice는 마지막 인덱스까지 동작
if (_end === undefined || _end > arr.length)
_end = arr.length;
// `start`가 배열의 범위를 벗어날 경우, 빈 배열을 리턴합니다.
let result = [];
for (let i = _start; i < _end; i++) {
result.push(arr[i]);
}
return result;
};
- slice 메소드 : 어떤 배열의 begin부터 end 까지 (end 미포함)에 대한 얕은 복사본을 새로운 배열 객체로 반환
- slice 메소드의 두 번째 인자가 음수인 경우 뒤에서 인덱스를 하나씩 카운트해서 요소를 제하고 출력해야 하는다는 것이 포인트
take
- _.take는 배열의 처음 n개의 element를 담은 새로운 배열 리턴
- n이 undefiend이거나 음수인 경우, 빈 배여 리턴
- n이 배열의 길이를 벗어날 경우, 전체 배열을 shallow copy한 새로운 배열 리턴
- 1. 내가 풀어본 방법
_.take = function (arr, n) {
let start = 0; //'start'가 undefined인 경우, 0부터 동작
let end = n; //받은 n이 마지막 인덱스
//'end'가 범위를 벗어날 경우 마지막 인덱스까지 동작
if(end > arr.length)
end = arr.length;
//'end'가 입력되지 않은 경우 빈배열 리턴
if(end === undefined) return [];
let result = [];
for(let i = start; i < end; i++){
result.push(arr[i]);
}
return result;
};
- 2. 줌 세션 시간에 설명해 주신 코드
_.take = function (arr, n) {
// _.slice 활용 ver.
// 0이 falsey한 값이라 0인게 ture 값이 될려면 !n --> n이 0이면 true가 나옴
if(!n) return [];
return _.slice(arr, 0, n);
};
drop
- _.drop는 _.take와 반대로, 처음 n개의 element를 제외한 새로운 배열 리턴
- n이 undefined이거나 음수인 경우, 전체 배열을 shallow copy한 새로운 배열 리턴
- n이 배열의 길이를 벗어난 경우 빈 배열 리턴
_.drop = function (arr, n) {
let start = n;
let end = arr.length; //마지막 인덱스 까지
//'start'가 입력되지 않은 경우 전체 배열 리턴
if(start === undefined)
start = 0;
let result = [];
for(let i = start; i < end; i++){
result.push(arr[i]);
}
return result;
};
last
- _.last는 배열의 마지막 n개의 element를 담은 새로운 배열 리턴
- n이 undefined이거나 음수인 경우, 배열의 마지막 요소만을 담은 배열을 리턴
- n이 배열의 길이를 벗어날 경우, 전체 배열의 shallow copy한 새로운 배열 리턴
- 1. 내가 풀어본 방법
_.last = function (arr, n) {
let start = arr.length-n;
let end = arr.length;
//n이 입력되지 않은 경우, 배열의 마지막 요소만 담은 배열 리턴
if(n === undefined)
start = arr.length-1;
//n 이 배열의 길이를 벗어날 경우, 배열 전체 리턴
if(n > arr.length)
start = 0;
let result = [];
for(let i = start; i < end; i++){
result.push(arr[i]);
}
return result;
};
- 2. 줌 세션 시간에 설명해 주신 코드
_.last = function (arr, n) {
// _.take과 _.drop 활용 ver
// n이 undefined일 경우 마지막 요소만 담은 배열 리턴
if(n === undefined)
return _.drop(arr, arr.length - 1);
// n이 배열의 길이를 벗어나면 전체 배열 리턴
if(n > arr.length)
return _.take(arr, arr.length);
else
return _.drop(arr, arr.length - n);
};
each
- _.each는 명시적으로 어떤 값을 리턴하지 않음
- _.each는 collection의 각 데이터에 반복적인 작업을 수행
- 1. collection과 함수 iteratee를 인자로 전달 받아
- 2. collection의 데이터를 순회하면서
- 3. iteractee(반복자)에 각 데이터를 인자로 전달하여 실행
- collection은 배열 혹은 객체, iteratee는 반복 작업, 콜백 함수
_.each = function (collection, iteratee) {
//배열을 입력받은 경우
if(Array.isArray(collection)) {
for(let i = 0; i < collection.length; i++){
iteratee(collection[i], i, collection); //iteratee(ele, inx, arr)
}
//객체를 입력 받은 경우
} else if(typeof collection === 'object') {
for(let key in collection){ //for..in 구문은 key값은 접근이 가능하나 value 값은 불가능
iteratee(collection[key], key, collection); //iteratee(val, key, obj)
}
}
};
indexOf
- _.indexOf는 target으로 전달되는 값이 arr의 요소인 경우, 배열에서의 위치(index)를 리턴
- 그렇지 않은 경우 -1를 리턴
- target이 중복해서 존재하는 경우, 가장 낮은 index를 리턴
_.indexOf = function (arr, target) {
// target이 arr의 요소가 아닌 경우
let result = -1;
_.each(arr, function (item, index) {
if (item === target && result === -1) {
result = index;
}
});
return result;
};
filter
- _.filter는 test 함수를 통과하는 모든 요소를 새로 담은 새로운 배열을 리턴
- test(element)의 결과(return)가 truthy일 경우 통과
- test는 각 요소에 반복 적용
- arr.filte(원하는 조건이 참이도록 작성한 함수)
_.filter = function (arr, test) {
let result = [];
//1. test라는 함수 안에 arr의 요소들이 인수로 하나씩 들어가야 함 --> test(arr의 요소들)
//2. test(arr의 요소들)를 통과한 값들만 담은 배열 리턴
_.each(arr, function (el) {
if(test(el)){ // 2.
result.push(el);
}
});
return result;
};
reject
- _.reject는 _.filter와 정반대로 test에 통과하지 못한 요소들만 담은 새로운 배열 리턴
_.reject = function (arr, test) {
let result = [];
_.each(arr, function(el){
if(!(test(el))){ //._filter에서 truthy한 요소들만 통화 시켰음. 이걸 단항 연산자 !를 사용해 뒤집음
result.push(el); //result에는 함수를 통과한 요소들만 있음
}
});
return result;
};
uniq
- _.uniq는 주어진 배열의 요소가 중복되지 않도록 새로운 배열을 리턴
- 중복 여부에 판단은 엄격한 동치 연산 (strict equality, ===)을 사용해야 함
- 입력으로 전달되는 배열의 요소는 모두 primitive라고 가정
- indexOf는 인수에 있는 배열의 값의 인덱스 값을 반환함. 중복 값은 가장 작은 인덱스 값을 가지는 인덱스 번호만 반환
- indexOf는 만약에 배열 안에 그 요소가 없으면 -1를 반환
_.uniq = function(arr){
let result = [];
_.each(arr,fucntion(el){
//1. 빈 배열 result라는 방을 만듬
//2. 요소들이 있는 arr이랑 result를 비교할 거임
//3. indexOf는 해당 요소의 인덱스 번호를 반환하는데 없으면 -1을 반환
//4. 빈 배열에 arr요소를 하나씩 넣음(-1이면 넣음, -1이 아니면 이미 있다는 뜻)
//5. 값이 같은 요소는 인덱스 번호가 작은 수만 리턴한다는 indexOf 특징으로 중복 거르기 가능
if(_.indexOf(result,el) === -1){
result.push(el);
}
});
return result;
};
map
- _.map은 iteratee(반복되는 작업)을 배열의 각 요소에 적용(apply)한 결과를 담은 새로운 배열 리턴
_.map = function (arr, iteratee) {
let result = [];
_.each(arr, function (el) {
result.push(iteratee(el));
});
return result;
};
pluck
- _.pluck는
- 1. 객체 또는 배열을 요소 갖는 배열과 각 요소에서 찾고자 하는 key또는 index를 입력 받아
- 2. 각 요소의 해당 값 또는 요소만을 추출하여 새로운 배열에 저장해 리턴
_.pluck = function (arr, keyOrIdx) {
//_.map(arr,함수) -> 함수에 arr 요소를 넣은 결과 값들이 출력 됨
//_.map 함수 자체를 요소를 순회할 수 있도록 구현해 놓았음
//두 번째 인자로 넣은 함수를 key나 index에 맞는 값을 추출하는 함수로 만들면 됨
let result = [];
_.map(arr,function(el){
result.push(el[keyOrIdx]);
});
return result;
};
reduce
- _.reduce는
- 1. 배열을 순회하며 각 요소에 iteratee함수(acc, ele, idx, arr) 를 적용하고,
- 2. 그 결과값을 계속 누적(accumulate)함
- 3. 최종적으로 누적된 결과값 리턴
- 리듀서 함수의 4가지 인자
- 1. 누산기(acc)
- 2. 현재값(cur)
- 3. 현재 인덱스(idx) : 현재 처리할 요소의 인덱스. initialValue를 적용한 경우 0, 아니면 1부터 시작
- 4. 원본 배열(src) : 리듀서 호출 배열
- reduce() 작동 방식
arr.reduce(function(acc,cur,idx,arr){
return acc + cur; // 누산식 예
}, initialValue);
_.reduce = function (arr, iteratee, initVal) {
let acc = initVal;
_.each(arr,function(el,idx,arr){
if(acc === undefined){ //1.초기값을 제공하지 않으면 배열의 첫번째 요소 사용
acc = arr[0];
} else {
acc = iteratee(acc, el, idx, arr); //2. 누산액에 할당
}
});
return acc;
};