(number, string, boolean, undefined, null, symbol)
값
자체가 저장배열, 객체
가 대표적인 참조 자료형, 함수
도 참조 자료형 !주소값
이 저장// 원시 자료형이 참조된 변수를 다른 변수에 할당
let num = 20;
let copiedNum = num;
// 참조 자료형이 할당된 변수를 다른 변수에 할당하기
let arr = [0, 1, 2, 3];
let copiedArr = arr;
// 두 변수가 같은지 확인하기 - 1
console.log(num === copiedNum); // true
console.log(arr === copiedArr); // true
// 원본을 변경하기
num = 30;
arr.push(4);
// 두 변수가 같은지 확인하기 - 2
console.log(num === copiedNum); // false
console.log(arr === copiedArr); // true
// 이 두 변수의 현재 상태는?
console.log(copiedNum); // 20
console.log(copiedArr); // [0, 1, 2, 3, 4]
let y = x;
slice()
를 통해 배열을 복사하여 heap에 다른 주소값으로 저장 가능let arr = [0, 1, 2, 3];
let copiedArr = arr.slice();
copiedArr.push(4);
console.log(arr); // [0, 1, 2, 3]
console.log(copiedArr); // [0, 1, 2, 3, 4]
// 주소가 다르기 때문에 원본배열에는 4가 추가되지 않음
let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = Object.assign({}, obj);
console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false (주소값이 다르기 때문)
const arr = [1, 2, [3, 4]];
const copiedArr = JSON.parse(JSON.stringify(arr));
console.log(arr); // [1, 2, [3, 4]]
console.log(copiedArr); // [1, 2, [3, 4]]
console.log(arr === copiedArr); // false
console.log(arr[2] === copiedArr[2]); // false
// console.log("code" === "code");
// console.log(3.14 === 3.14);
// console.log([1, 2, 3] === [1, 2, 3]);
// console.log({ foo: "bar" } === { foo: "bar" });
// let x = { foo: 3 };
// let y = x;
// y = 2; // 위 주소값을 없애고 원시 자료형이 새로 할당
// console.log(y);
// let myArr = [2, 3, 4, 5];
// let ourArr = myArr;
// ourArr[2] = 25;
// ourArr = undefined; // 주소값에 undefined, 배열엔 영향 x
let player = { score: 3 };
function doStuff(obj) {
obj.score = 2;
}
doStuff(player);
console.log(player.score);
사용 가능
<->사용 불가
// 밖에서 `let message;`해줄 경우에는 `'Hello kimcoding'` 출력
let username = "kimcoding";
// let message;
if (true) {
message = `Hello, ${username}!`;
console.log(message); // 'Hello kimcoding'
}
console.log(message); // ReferenceError
// 지역 변수 name을 선언하고 초기화하기 때문에 함수 밖에서는 효력x
let name = "김코딩";
function showName() {
let name = "박해커"; // 지역변수
console.log(name);
}
console.log(name); // ?
showName(); // ?
console.log(name); // ?
----------------------------------------
// 외부에 있는 전역 변수 name을 직접 변경하기때문에 함수 이후에 출력되는 name은 모두 "박해커"로 변경
let name = "김코딩";
function showName() {
let name = "박해커";
console.log(name);
}
console.log(name); // ?
showName(); // ?
console.log(name); // ?
outerFn
에서는 변수 globalVar
에 접근할 수 있습니다.innerFn
에서는 변수 globalVar
와 함수 outerFn
내부의 outerFnVar
에 접근할 수 있습니다.즉, 위 코드에서 클로저는 두 조합을 찾을 수 있었습니다.
outerFn
과 outerFn
에서 접근할 수 있는 globalVar
innerFn
과 innerFn
에서 접근할 수 있는 globalVar
, outerFnVar
innerFn()
을 반환하는하는 대신 innerFn
를 리턴// 클로저 사용 패턴 1
function outerFn() {
const outerFnVar = 'outer 함수 내의 변수';
const innerFn = function() {
return 'innerFn은 ' + outerFnVar + '에 접근할 수 있습니다.';
}
return innerFn;
}
// createFoodRecipe(foodName)에서 getFoodRecipe을 리턴해서 getFoodRecipe()에 접근 가능하게 함(기존 스코프에서 불가능한 것(외부에서 내부로 접근 가능하게 하는 것)을 사용 가능하게 만든 것이 클로저)
function createFoodRecipe (foodName) {
const getFoodRecipe = function (ingredient1, ingredient2) {
return `${ingredient1} + ${ingredient2} = ${foodName}!`;
}
return getFoodRecipe;
}
const highballRecipe = createFoodRecipe('하이볼');
highballRecipe('콜라', '위스키'); // '콜라 + 위스키 = 하이볼!'
highballRecipe('탄산수', '위스키'); // '탄산수 + 위스키 = 하이볼!'
highballRecipe('토닉워터', '연태고량주'); // '토닉워터 + 연태고량주 = 하이볼!'
return function
구조는 클로저임을 암묵적으로 알려주며 익명함수이기도 하다. 익명함수는 보안적인 부분에서 유리```jsx
function makePancake(powder) {
return function (sugar) {
return function (pan) {
return `팬케이크 완성! 재료: ${powder}, ${sugar} 조리도구: ${pan}`;
}
}
}
const addSugar = makePancake('팬케이크가루');
const cookPancake = addSugar('백설탕');
const morningPancake = cookPancake('후라이팬');
// 잠깐 낮잠 자고 일어나서 ...
const lunchPancake = cookPancake('후라이팬');
function makePancakeAtOnce (powder, sugar, pan) {
return `팬케이크 완성! 재료: ${powder}, ${sugar} 조리도구: ${pan}`;
}
const morningPancake = makePancakeAtOnce('팬케이크가루', '백설탕', '후라이팬')
// 잠깐 낮잠 자고 일어나서 만든 팬케이크를 표현할 방법이 없다.
function sum(x, y, z) {
return x + y + z;
}
const numbers = [1, 2, 3];
// 아래 두 코드는 같은 코드
// console.log(numbers[0] + numbers[1] + numbers[2]);
console.log(sum(...numbers));
let arr = [1, 2, 3];
let arr2 = [...arr]; // arr.slice() 와 유사
arr2.push(4); // 참고: spread 문법은 기존 배열을 변경하지 않으므로(immutable), arr2를 수정한다고, arr이 바뀌지 않습니다.
console.log(arr);
console.log(arr2);
// 질문: arr와 arr2의 값은 각각 무엇인가요?
// [ 1, 2, 3 ]
// [ 1, 2, 3, 4 ]
function sum(...theArgs) {
let result = 0;
for(let i = 0; i < theArgs.length; i++) {
result += theArgs[i];
}
return result;
}
sum(1,2,3) // 질문: 어떤 값을 리턴하나요?
sum(1,2,3,4) // 질문: 어떤 값을 리턴하나요?
// 함수선언문
function sum (x, y) {
return x + y;
}
// 함수표현식
const subtract = function (x, y) {
return x - y;
}
(=>)
를 사용// 화살표 함수
const multiply = (x, y) => {
return x * y;
}
()
)를 생략할 수 있다// 매개변수가 한 개일 때, 소괄호를 생략할 수 있습니다.
const square = x => { return x * x }
// 위 코드와 동일하게 동작합니다.
const square = ( x ) => { return x * x }
// 단, 매개변수가 없는 경우엔 소괄호를 생략할 수 없습니다.
const greeting = () => { return 'hello world' }
{}
)를 생략할 수 있다. 이때 코드 블록 내부의 문이 값으로 평가될 수 있으면 return 키워드를 생략할 수 있다. (= 중괄호가 사라지면 return문도 사라짐)const squre = x => x * x
// 위 코드와 동일하게 동작합니다.
const square = x => { return x * x }
// 위 코드와 동일하게 동작합니다.
const square = function (x) {
return x * x
}