let a = 1;
let b = a;
b = 2; // a = 1 그대로
배열([]), 객체({}), 함수(function(){})
let e = [10, 20];
let f = e;
f[0] = 50;
e; // e = [50, 20] 으로 변함.
// 문제 3) console.log('codestates' === 'codestates'); //true console.log(3.14 === 3.14); //true // 참조 자료형의 ===(strict equality)는 주소값이 같은지를 확인, // 따라서 두 참조 자료형의 주소값은 다르다고 판단을 내릴 수 있음. console.log([1,2,3] === [1,2,3]); //false console.log({ foo: 'bar' } === { foo: 'bar' }); //false // 문제 4) let x = { foo: 3 }; let y = x; //여기서 변수 y는 x의 주소값을 할당 받음. y = 2; //하지만 다시 2라는 값을 할당 받음. 따라서 x.foo는 변함없이 3이다. // 문제 7) let score = 80; function doStuff(value) { value = 90; } doStuff(score) // score 값은 80 //매개변수 value에 score의 값 80이 전달되고,```
- message라는 변수 자체가 중괄호(블록) 안쪽에 선언되어 있으므로, 바깥쪽에서는 접근할 수 없다. 바깥쪽에서는 접근이 불가능하면 ReferenceError를 낸다.
- 예제3) 정답 : 김코딩 박해커 김코딩
- 첫번째 출력은 첫째 줄에서 전역 변수로 선언된 name을 가져옴. (showName 함수 안쪽에 선언된 지역 변수 name은 애초에 스코프 규칙에 의해 접근할 수 없다.) "김코딩"을 출력.
두번째 출력은 함수 안에서 선언한 name이라는 지역 변수에 접근. 변수 이름이 전역 변수와 똑같지만, 지역 변수가 전역 변수보다 우선순위가 높으므로, 쉐도잉(variable shadowing)현상(동일한 변수 이름으로 인해 바깥쪽 변수가 안쪽 변수에 의해 가려지는 현상)으로 지역 변수 name이 출력.
두번째 출력은 "박해커.
세번째 출력은 첫번째 출력과 마찬가지로 전역 변수 name을 출력. 지역 변수에 선언된 name 변수는 안쪽 스코프이므로 접근이 불가능. 따라서 "김코딩"을 출력.
- 예제4) 정답 : 김코딩 박해커 박해커
- 세번째 줄에서 let 키워드를 사용한 선언이 존재하지 않음. 이는, '박해커'라는 값으로 할당하고 있는 name 변수는 전역에 선언된 name 변수를 그대로 사용하겠다는 의미!!!
지역 스코프에서 새로 선언되지 않으면 그냥 같은 변수이므로 showName 함수가 실행되기 전, 처음에는 '김코딩'을 출력하고, 그 이후에는 전역변수 name의 값이 바뀌기 때문에 두번째 및 세번째 출력에 '박해커'가 출력된다.
- block scope : 블록 스코프 : {중괄호}로 둘러싼 범위
- 화살표 함수는 블록 스코프로 취급됨 ! : 화살표 함수로 둘러싼 범위
- function scope : 함수 스코프 : f( ){함수}로 둘러싼 범위
- 함수 스코프와 블록 스코프는 논리적인 구분 외에도 코드를 작성할 때 기억해야 할 다른 점이 몇 가지 존재
let | const | var | |
---|---|---|---|
유효범위 | 블록 스코프 및 함수 스코프 | 블록 스코프 및 함수 스코프 | 함수 스코프 |
값 재할당 | 가능 | 불가능 | 가능 |
재선언 | 불가능 | 불가능 | 가능 |
- let
- 블록 스코프 안에서 정의된 변수 i
let i = 0;
는 블록 범위를 벗어나는 즉시 접근할 수 없다.- 블록 스코프, 화살표 함수, 함수 스코프 따른다.
- 재선언 방지함.
- var
- 블록 스코프 무시, 화살표 함수, 함수 스코프만 따른다.
- 재선언해도 에러 없음 - side effect 발생
- 혼란을 줄 수 있으므로 let 키워드 사용이 권장 됨.
- var 키워드보다 let 키워드가 더 안전한 이유
: var 키워드는 재선언을 해도 아무런 에러도 내지 않지만, let키워드는 재선언을 방지하므로써 버그를 막아준다.
- const
- 블록 스코프, 화살표 함수, 함수 스코프 따른다.
- 값의 변경을 최소화하여 보다 안전한 프로그램을 만들 수 있다. 값을 새롭게 할당할 일이 없다면 const 키워드의 사용이 권장됨.
- 재할당 방지함. 재할당하는 경우, TypeError.
: Local Scope와 Global Scope 확인 가능
: debugger + (shift + enter)
'use strict'
라고 입력.1. 함수를 리턴하는 함수.
2. 외부함수와 내부함수 : 리턴하는 함수에 의해 스코프(변수의 접근 범위)가 구분됨.
클로저의 핵심은 스코프를 이용해서 변수의 접근 범위를 닫는(closure; 폐쇄) 데에 있다. 따라서, 함수를 리턴하는 것만큼이나, 변수가 선언된 곳이 중요!
클로저 함수 : 외부함수의 변수에 접근 가능한 내부함수.
1. 데이터를 보존하는 함수
: 일반적인 함수는, 함수 실행이 끝나고 나면 함수 내부의 변수를 사용할 수 없다. 이와 다르게, 클로저는 외부 함수의 실행이 끝나더라도, 외부 함수 내 변수가 메모리 상에 저장된다. 변수 add5 에는 클로저를 통해 리턴한 함수가 담겨 있다. add5 는 adder함수에서 인자로 넘긴 5라는 값을 (외부 함수의 실행이 끝났음에도!!)x 변수에 계속 담은 채로 남아있다.
2. 정보의 접근 제한
: 클로저를 이용해 내부 함수를 단 하나만 리턴하는 것에 그치지 않고, 객체에 담아 여러 개의 내부 함수를 리턴하도록 만들 수 있다.
: makeCounter 함수는 "increase, decrease, getValue메소드를 포함한 객체"를 리턴. counter1은 객체다.
: '외부 스코프에서는 내부 스코프의 변수에 접근할 수 없다'는 규칙에 의해, 어떤 경우에도 value
는 직접 수정이 불가능. 대신, 리턴하는 객체가 제공하는 메소드를 통해 value
값을 간접적으로 조작 가능. =========> "정보의 접근 제한 (캡슐화)" : value의 값을 보존해줌.
정보의 접근 제한 (캡슐화)
: 만일 스코프로 value 값을 감싸지 않았더라면, value 값은 전역 변수여야만 했다. 하지만 makeCounter라는 함수가 value 값을 보존하고 있기 때문에, 전역 변수로 따로 만들 필요가 없었다. 전역 변수는 다른 함수 혹은 로직 등에 의해 의도되지 않은 변경(side effect)을 초래하여 좋지 않다. side effect를 최소화하면, 의도되지 않은 변경을 줄일 수 있다. 따라서 이에 따른 오류로부터 보다 안전하게 값을 보호 가능.
정보의 접근 제한 (캡슐화) 장점 : 클로저를 통해 불필요한 전역 변수 사용을 줄이고, 스코프를 이용해 값을 보다 안전하게 다룰 수 있다.
: makeCounter에 의해 리턴된 객체는, makeCounter를 실행할 때에 선언되는 value 값을 각자 독립적으로 가진다. 따라서 counter1에서의 value와 counter2에서의 value는 서로에게 영향을 끼치지 않고(각각 주소가 아닌 객체 자체가 할당되므로...), 각각의 값을 보존할 수 있다. 함수 재사용성을 극대화하여, 함수 하나를 완전히 독립적인 부품 형태로 분리하는 것을 "모듈화"라고 한다.
클로저를 통해 데이터와 메소드를 같이 묶어서 다룰 수 있다!! 즉, 클로저는 모듈화에 유리하다!
!! Spread/Rest 문법 , 구조 분해 알아두면 편리 mdn 숙지하기 !!
Spread 문법 - mdn
유사배열
!! Spread/Rest 문법 , 구조 분해 알아두면 편리 mdn 숙지하기 !!
function sum(x, y, z) {
return x + y + z;
}
const numbers = [1, 2, 3];
sum(...numbers) // 질문: 어떤 값을 리턴하나요? 6
let arr = ['code', 'states']
let value = [
...arr,
'pre',
...['course', 'student']
]
//['code', 'states', 'pre', 'course', 'student']
function sum(...theArgs) {
return theArgs.reduce((previous, current) => {
return previous + current;
});
}
sum(1,2,3) // 질문: 어떤 값을 리턴하나요? 6
sum(1,2,3,4) // 질문: 어떤 값을 리턴하나요? 10
let parts = ['shoulders', 'knees'];
let lyrics = ['head', ...parts, 'and', 'toes'];
// 질문: lyrics의 값은 무엇인가요? ['head', 'shoulders', 'knees', 'and', 'toes']
let arr1 = [0, 1, 3];
let arr2 = [3, 4, 5];
arr1 = [...arr1, ...arr2]; // arr1 = [0, 1, 3, 3, 4, 5]
// 참고: spread 문법은 기존 배열을 변경하지 않으므로(immutable),
// arr1의 값을 바꾸려면 새롭게 할당해야 합니다.
let arr = [1, 2, 3];
let arr2 = [...arr]; // arr.slice() 와 유사
arr2.push(4); // 참고: spread 문법은 기존 배열을 변경하지 않으므로(immutable),
//arr2를 수정한다고, arr이 바뀌지 않습니다.
// 질문: arr와 arr2의 값은 각각 무엇인가요?
let obj1 = { foo: 'bar', x: 42 };
let obj2 = { foo: 'baz', y: 13 };
let clonedObj = { ...obj1 }; // {foo: 'bar', x: 42}
let mergedObj = { ...obj1, ...obj2 }; // {foo: 'baz', x: 42, y: 13}
// 질문: clonedObj와 mergedObj의 값은 각각 무엇인가요?
function myFun(a, b, ...manyMoreArgs) {
console.log("a", a);
console.log("b", b);
console.log("manyMoreArgs", manyMoreArgs);
}
myFun("one", "two", "three", "four", "five", "six");
// 질문: 콘솔은 순서대로 어떻게 찍힐까요
//a one
//b two
//manyMoreArgs (4) ['three', 'four', 'five', 'six']
let x;
let y;
let man;
function myFun(a, b, ...manyMoreArgs) {
x = a;
y = b;
man = manyMoreArgs;
}
myFun("one", "two", "three", "four", "five", "six");
console.log(x);
console.log(y);
console.log(man);
// 질문: 콘솔은 순서대로 어떻게 찍힐까요
//one
//two
// (4) ['three', 'four', 'five', 'six']
: 구조 분해 할당 구문은 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식입니다.
const [a, b, ...rest] = [10, 20, 30, 40, 50];
// 질문: a, b, rest는 각각 어떤 값인가요?
// 10
// 20
// [30, 40, 50]
const {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}
// 질문: a, b, rest는 각각 어떤 값인가요?
// 10
// 20
// {c: 30, d: 40}
function whois({displayName: displayName, fullName: {firstName: name}}){
console.log(displayName + " is " + name);
}
let user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
whois(user) // 질문: 콘솔에서 어떻게 출력될까요? jdoe is John
let arr = [10, 30, 40, 20]
let value1 = Math.max(arr) // NaN
let value2 = Math.max(...arr) // 40