2021.04.30
1. 비동기란?
2. map, slice
- map
3. 피셔-예이츠 셔플 알고리즘
4. sort()
5. setTimeout()
6. var와 let의 차이(feat.클로저)
- 변수
- 실습파일
var과 let의 차이
에 설명이 있다.map, slice
slice
는(자르기 시작할 인덱스, 끝 인덱스) 다만, 끝 인덱스는 자르기 대상에 포함하지 않는다.
array.map(callbackFunction(currentValue, index, array),thisArg)
map()
함수는 모든 배열의 값이 Function
을 실행하는 메소드다!callbackFunction
을 실행한 결과를 가지고 새로운 배열을 만들 때 사용한다.callbackFunction, thisArg
총 두개의 매개변수가 있고, callbackFunction
은 currentValue,index,array
3개의 매개변수를 갖는다.
currentValue
: 배열 내 현재 값.index
: 배열 내 현재 값의 인덱스.array
: 현재 배열thisArg
: callbackFunction
내에서 this
로 사용될 값.const days = ["Mon", "Tue", "Wed", "Thus", "Fri"];
위와 같은 변수가 있다고 하자.
여기서 days.map(…)을 적용한다는 것은 `days`에 있는 모든 요소에 `Function`을 실행하고 `Function`에서 나오는 값을 저장해서 새로운 배열로 만든다는 것이다. (그러므로 원본은 변하지 않는다.)
간단하게 square root (제곱근)을 구해보자
const numbers = [4, 9, 16, 25, 36];
const result = numbers.map(Math.sqrt);
console.log(result);
result[(2, 3, 4, 5, 6)];
이번에는 기존 배열에 값의 x2를 한 배열을 생성해 보자.
다음 세 개는 결과가 같다.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const newNumbers = numbers.map((number) => number * 2);
console.log(newNumbers);
result[(2, 4, 6, 8, 10, 12, 14, 16, 18)];
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const newNumbers = numbers.map(function (number) {
return number * 2; // 이렇게 해도 결과는 위와 같다.
});
console.log(newNumbers);
result[(2, 4, 6, 8, 10, 12, 14, 16, 18)];
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
function multiplyTwo(number) {
return number * 2;
}
const newNumbers = numbers.map(multiplyTwo);
console.log(newNumbers); // 이렇게 해도 결과가 같다.
result[(2, 4, 6, 8, 10, 12, 14, 16, 18)];
위의 결과들은 다 같다.
numbers에 곱하기 2한 값이 newNumbers에 똑같이 나타난다.
map 함수는 기존의 배열을 callbackFunction에 의해 새 배열을 만드는 함수이다.
그러니 기존의 배열이 변하지는 않는다.
map
함수는 filter함수와 같이 Object(객체)타입도 컨트롤 할 수도 있다.
const students = [
{ id: 1, name: "james" },
{ id: 2, name: "tim" },
{ id: 3, name: "john" },
{ id: 4, name: "brian" },
];
이러한 Object(객체)타입의 변수가 있다.
여기서 이름만 추출하고 싶으면 Array map을 이용해서 쉽게 추출할 수 있다.
const students = [
{ id: 1, name: "james" },
{ id: 2, name: "tim" },
{ id: 3, name: "john" },
{ id: 4, name: "brian" },
];
const names = students.map((student) => student.name);
console.log(names);
result[("james", "tim", "john", "brian")];
result를 보면 이름만 추출된 것을 볼 수 있다.
여기서 student.name을 student.id로 바꾸면 id 값만 추출된다.
const students = [
{ id: 1, name: "james" },
{ id: 2, name: "tim" },
{ id: 3, name: "john" },
{ id: 4, name: "brian" },
];
var names = students.map((student) => student.id);
console.log(names);
result[(1, 2, 3, 4)];
결과를 보면 id 값만 추출된 것을 볼 수 있다.
또다른 Object(객체)를 보자.
const testJson = [
{name : "이건", salary : 50000000},
{name : "홍길동", salary : 1000000},
{name : "임신구", salary : 3000000},
{name : "이승룡", salary : 2000000}
];
const newJson = testJson.map(function(element, index){
console.log(element);
const returnObj = {};
returnObj[element.name] = element.salary;
return returnObj;
});
console.log("newObj");
console.log(newJson);
result
1. console.log(element);
{ name: '이건', salary: 50000000 }
{ name: '홍길동', salary: 1000000 }
{ name: '임신구', salary: 3000000 }
{ name: '이승룡', salary: 2000000 }
2. console.log(newJson);
[{ '이건': 50000000 },{ '홍길동': 1000000 },{ '임신구': 3000000 },{ '이승룡': 2000000 }]
이번에는 Array를 reverse.
배열 값에 곱하기 2한 값들을 reverse한다.
```javascript
const numbers = [1,2,3,4,5,6];
const numbersReverse = numbers.map(number => number *2).reverse();
console.log(numbersReverse);
result
[ 12, 10, 8, 6, 4, 2 ]
```
Array
안에 Array
가 있는 경우
const numbers = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]; //array안에 array가 있는 경우
const newNumbers = numbers.map((array) =>
array.map((number) => number * 2)
);
console.log(newNumbers);
result[([2, 4, 6], [8, 10, 12], [14, 16, 18])];
while (candidate.length > 0) {
//무작위 인덱스 뽑기.
const random = Math.floor(Math.random() * candidate.length);
//무작위 인덱스로 뽑은 값은 spliceArray배열에 들어있다.
const spliceArray = candidate.splice(random, 1);
//배열에 들어있는 값을 꺼낸다.
const value = spliceArray[0];
//shuffle배열에 삽입.
shuffled.push(value);
}
숫자를 무작위로 섞는 방법이다. 먼저 무작위 인덱스를 하나 선택한 후, 그에 해당하는 요소를 새로운 배열로 옮긴다. 이를 반복하다 보면 새 배열에 무작위로 섞인 숫자들이 들어간다.
sort()
array.sort(function(a,b){a-b};); --> array.sort((a,b)=>{a-b};)
[1,2,3,4,5,6,7,8,9]
가 나온다.[9,8,7,6,5,4,3,2,1]
이 나온다.array.slice().sort((a,b)=>{a-b})
setTimeout()
setTimeout(() => {
//실행문
}, millisecond);
setTimeout
에 지정된 작업이 수행되지 않는다. 기존에 하고 있던 일이 끝나야 setTimeout
에 지정한 작업이 실행된다.var와 let의 차이
(feat.클로저)내가 면접 때 오지게 절었던 부분 중 하나
실습파일(lotto.html)의 for문에서 let i = 0 을 var i = 0
으로 바꾸면 undefined 6
이 나온다.즉, 모든 i가 6으로 나온다는 것이다.
변수
스코프
라는 것을 가진다. var
는 함수 스코프를 가지고 let
은 블록 스코프를 가진다.function b(){
var a = 1;
}
console.log(a);
result
Uncaught ReferenceError: a is not defined
var a
를 정의한 후 함수 바깥에서 변수 a를 호출했더니 에러가 발생했다. 이유인 즉슨 var는 함수 내에서만 동작하는 지역변수이기 때문이다.이와 같이 함수를 경계로 접근 여부가 달라지는 것
을 함수 스코프라고 한다.if (true) {
var a = 1;
}
console.log(a);
result;
1;
함수 범위에 없고 조건문 내에 있기 때문에 a값이 그대로 출력되는 것을 볼 수 있다.
즉, 함수만 신경쓴다는 것인데 let
은 조금 다르다.
if(true){
let a = 1;
}
console.log(a);
result
Uncaught ReferenceError: a is not defined
if, switch, for, while(?얘는 case by case)
등의 함수가 아닌 블록 내부
에서만 접근이 허용된다는 것을 유추할 수 있다.lotto.html
)for (var i = 0; i < winBalls.length; i++) {
setTimeout(() => {
console.log(winBalls[i], i);
drawBall(winBalls[i], $result);
}, (i + 1) * 1000);
}
위의 코드 중
() => {
console.log(winBalls[i], i);
drawBall(winBalls[i], $result);
};
이 부분은 실제 코드와 다른 시점에 실행
된다. 위 코드가 실행이 될 때는 i값은 이미 6이 되어있다.
즉
for루프를 모두 돌고 i값이 6이 된다
-> 1초가 된다
-> winBalls[6]이 나온다
-> winBalls[6]은 winBalls배열의 범위(5)를 넘었기에 undefined로 나온다
-> log값이 'undefined 6'으로 출력된다
라는 일련의 과정으로 이해할 수 있다`.
나중에 커서 보고 이해 못하는 나 또는 다른 분들에겐 친절하게 루프로 보여주겠다.
i가 6이 됨
1초 후 콜백 0실행(i=6)
2초 후 콜백 0실행(i=6)
3초 후 콜백 0실행(i=6)
4초 후 콜백 0실행(i=6)
5초 후 콜백 0실행(i=6)
6초 후 콜백 0실행(i=6)
let
을 쓸 때는 이러한 문제가 발생하지 았았는가?for (let i = 0; i < winBalls.length; i++) {
setTimeout(() => {
console.log(winBalls[i], i);
drawBall(winBalls[i], $result);
}, (i + 1) * 1000);
}
for
문에서 쓰이는 let
은 하나의 블록마다 i
가 고정된다. 이것도 블록 스코프의 특성이라고 보면 된다.
따라서 setTimeout
콜백 함수 내부의 i
도 setTimeout
을 호출할 떄의 i
와 같은 값이 들어간다.
그래서 나온게(?) 클로저
다. 아래를 보자.
for (var i = 0; i < winBalls.length; i++) {
//함수를 소괄호로 감싼다 = 그 자리에서 바로 호출한다.
(function (j) {
//j는 매개변수이고 함수블록 안에 갇혀있다.
setTimeout(() => {
console.log(winBalls[j], j); // 함수의 인자j는 for문의 var i를 가리킨다.
drawBall(winBalls[j], $result);
}, (i + 1) * 1000);
})(i);
}
클로저는 함수와 함수 바깥에 있는 변수와의 관계
다.
함수 바깥에 있는 변수를 함수 안에 있는 변수로 바꿔주고 내부 함수의 변수로써 사용하도록 억지 세팅해준거다 그냥 let
쓰자…
그래도 난 개발지식이 태아수준이라 현상 자체는 알아야 한다.
함수랑 함수 자체를 바깥에 있는 변수들을 통틀어 클로저
라 칭하고 그 클로저
와 variable
이 만나면 위의 문제가 발생할 수 있다. 근데 모든 케이스가 그렇지 않고 조건이 껴있다. 바로 비동기
다.
즉 함수 스코프를 지닌 variable
과 비동기함수
가 만나면 클로저문제
가 발생한다. 그렇다고 무조건 let
을 쓰는것은 좋지 않다 왜냐하면 레거시코드에서 var
을 쓰는 경우가 있기 때문에 해당 현상에 대해서 충분히 이해하고 설명할 수 있어야 한다.