코딩응애의 개발블로그

코드스테이츠 15일차 - ([JavaScript] 클로저,spread,구조분해할당) & 회고 본문

카테고리 없음

코드스테이츠 15일차 - ([JavaScript] 클로저,spread,구조분해할당) & 회고

이너멜 2022. 7. 12. 15:00

클로저 

외부 함수의 변수에 접근할 수 있는 내부함수를 클로저 함수라고 한다. 근데 이거 가지고는 이해가 안가서 유튜브 영상 몇개 더봄 

클로점 함수 특징

1.함수를 리턴하는 함수

2.내부 함수는 외부 함수에 선언된 변수에 접근 가능하다

하지만 단순히 함수를 리턴한다고 클로저 함수가 되는 것은 아니다. 

이제 유튜브 보고 알게된 내용 정리 

 

if(1<2) {
	let f = function() {
        let abc = 123;
    }
    f();
    console.log(abc); // 이렇게 쓰면 오류가 남 왜냐면...
}

함수가 실행되고 난 다음 시점에는 함수 안에서 만든 변수 이름들은 그 밖에서는 접근이 불가능하기 때문에 오류가 나는 것이다.

더이상 abc에 접근할 방법이 없기 때문에 그 메모리에 있는 123은 접근할 방법이 없어서 쓸모 없는 자료가 돼서 사라진다.

근데 함수가 종료가 된 시점에도 변수에 접근할 수 있다면 함수가 끝나도 123은 사라지지 않음 그렇게 만든 코드가 바로 ..

if(1<2) {
	let f = function() {
    	let abc = 123;
        let ddd = function() {
            return abc;
        }
        return ddd;
    }
    let ccc = f();
    console.log(ccc()); // 결과로 123이 나옴 
}

변수 cnt가 있는데 cnt 라는 값은 cntPlus() 함수로만 바꾸고 싶은 조건이 있다고 가정하고 함수 구현 해보면 

let cnt = 0;
function cntPlus() {
    cnt = cnt + 1;
}

console.log(cnt); // 0 출력 
cntPlus();
console.log(cnt); // 1 출력

cnt = 100;
cntPlus();
console.log(cnt); // 101 출력

근데 만약 위에 코드처럼 cnt에 100을 할당하고 함수를 실행 시키면 cnt는 101 이 되어버림.

근데 이렇게 되면 cntPlus()로만 cnt 값을 바꾸고자 했던 조건을 위배하게 됨.

중간에 cnt라는 변수가 접근이 가능하기 때문에  완벽하게 구할 수 가 없게됨.

그래서 중간에 변수를 접근 못하게 해야 하는데 그때 필요한게 클로저 함수이다

function closure() {
    let cnt = 0;
    function cntPlus() {
        cnt = cnt + 1;
    }
    return {
    	cntPlus,
    }
}

const cntClosure = closure();
console.log(cntClosure); // {cntPlus : [Function:cntPlus]} 출력

그럴러면 우선 cnt 변수가 전역 변수이기 때문에 지역 변수로 만들어 주어야 한다. 그때는 함수로 감싸준다.

이젠 밖에서 cnt 변수 접근하려 해도 클로저 함수에 지역변수 이기 때문에 밖에서 참조를 할 수 없게된다. 

그치만 이렇게 해버리면 cntPlus() 함수를 실행시킬 수도 없게되어버린다. 

이때 함수를 리턴을 해주어야 함

콘솔로 출력을 하면 cntClosure는 객체고 이 객체에는 cntPlus라는 키값을 가지는 cntPlus라는 함수가 담겨져 있는걸 알 수 있다.

이제 cntPlus 함수를 실행 시키면 cnt 값이 1 증가할 것이다. 

function closure() {
    let cnt = 0;
    function cntPlus() {
        cnt = cnt + 1;
    }
    function printCnt() {
    	console.log(cnt); // cntPlus 함수 실행 후 cnt 값이 증가 됬는지 확인하기 위한 함수
    }
    return {
    	cntPlus,
        printCnt
    }
}

const cntClosure = closure();
console.log(cntClosure); 
cntClosure.printCnt(); // 0 출력
cntClosure.cntPlus(); // 함수 실행 
cntClosure.printCnt(); // 1 출력

그렇다면 중간에  변수 cnt의 값을 바꿀수 있는 방법이 있을까? 절대 없다.

값을 따로 주거나 할려면 새로운 함수를 만드는 수 밖에 없음. 클로저 함수는 이런식으로 사용한다. 

 

spread 연산자 

배열, 문자열, 객체 등 반복 가능한 객체 (Iterable Object)를 개별 요소로 분리할 수 있다. 

기존의 것은 건들이지 않고 새로운 객체를 만들 때 사용한다.

우선 배열에서 사용할때 두개의 배열을 병합하는데 사용할 수 있다. concat 메소드를 이용할 수 도 있지만

let arr1 = [1,2,3]; 
let arr2 = [4,5,6]; 

let arr = [...arr1, ...arr2]; 
console.log(arr); // [ 1, 2, 3, 4, 5, 6 ] 출력

let arr1 = [1,2];
let arr2 = [0, ...arr1, 3, 4];

console.log(arr2); // [0, 1, 2, 3, 4] 출력

const animals = ['개', '고양이', '참새'];
const anotherAnimals = [...animals, '비둘기'];
console.log(animals); // ['개', '고양이', '참새'] 출력 
console.log(anotherAnimals); // ['개', '고양이', '참새','비둘기'] 출력

여기서 중요한건 기존의 것(원본 배열)은 건들이지 않는다는 것이다. 

객체 또한 마찬가지로 주소 참조가 아닌 값을 복사해서 기존의 값은 변경되지 않는다. 

const myInfo = {name: 'AYW', age:27,  marriage: false}
const newInfo = {...myInfo}
console.log(newInfo) // {name: 'AYW', age:27,  marriage: false}

const firstInfo = {name: 'AYW'}
const secondInfo = {age: 27}
const resultInfo = {...firstInfo, ...secondInfo}
console.log(resultInfo) // {name: 'AYW', age:27}

const myInfo = {name: 'AYW', age:27,  marriage: false}
const newInfo = {...myInfo, marriage: !myInfo.marriage}
console.log(newInfo) // {name: 'AYW', age:27,  marriage: true}

rest

spread와 생김새는 비슷하지만 역할은 매우 다르다. 객체, 배열, 그리고 함수의 파라미터에서 사용이 가능

사용할때 rest 라는 키워드를 사용하는데 꼭 rest라고 쓸 필요는 없다 

rest는 객체와 배열에서 사용할 때는 구조 분해 할당 문법과 함께 사용된다

// 객체에서 사용할때 
const purpleCuteSlime = {
  name: '슬라임',
  attribute: 'cute',
  color: 'purple'
};

const { color, ...rest } = purpleCuteSlime;
console.log(color); // 'purple'
console.log(rest); // { name: '슬라임', attribute: 'cute'}


const purpleCuteSlime = {
  name: '슬라임',
  attribute: 'cute',
  color: 'purple'
};

const { attribute, color, ...rest } = purpleCuteSlime;
console.log(color); // 'purple'
console.log(rest); // { name: '슬라임'}

// 배열에서 사용할때 
const numbers = [0, 1, 2, 3, 4, 5, 6];

const [one, ...rest] = numbers;

console.log(one); // 0
console.log(rest); // [1, 2, 3, 4, 5, 6]

// 함수에 사용할때 
// 함수의 파라미터가 몇개가 될 지 모르는 상황에서 rest 파라미터를 사용하면 매우 유용
function sum(...rest) {
  return rest;
}

const result = sum(1, 2, 3, 4, 5, 6);
console.log(result); // [1, 2, 3, 4, 5, 6]

출처 : https://learnjs.vlpt.us/useful/07-spread-and-rest.html   (함수에서 spread 사용법도 보기) 

 

구조분해할당

배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식입니다.

객체나 배열을 변수로 '분해’할 수 있게 해주는 특별한 문법.

객체,배열을 사용하면 쉽게 데이터 뭉치를 만들 수 있는데 구조분해할당 구문은 이와 비슷하지만 대신 할당문의 좌변에서 사용하여, 원래 변수에서 어떤 값을 분해해 할당할지 정의합니다.

const x = [1, 2, 3, 4, 5];
const [y, z] = x;
console.log(y); // 1
console.log(z); // 2
---------------------------------------------------
const foo = ["one", "two", "three"];

const [red, yellow, green] = foo;
console.log(red); // "one"
console.log(yellow); // "two"
console.log(green); // "three"
-------------------------------------------------------
let arr = ["Bora", "Lee"]
let [firstName, surname] = arr; // 구조 분해 할당을 이용해 firstName엔 arr[0]을 surname엔 arr[1]을 할당.
------------------------------------------------------------
let firstName = arr[0];
let surname = arr[1]; // 이 두줄짜리 코드와 let [firstName, surname] = arr;는 같은 의미이다.
-----------------------------------------------------

 

rest를 이용해서 나머지 요소를 가져올 수 도 있다. 단 변수 앞의 점 세 개(...)와 변수가 가장 마지막에 위치해야 한다.

let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];

console.log(name1); // Julius
console.log(name2); // Caesar

// `rest`는 배열입니다.
console.log(rest[0]); // Consul
console.log(rest[1]); // of the Roman Republic
console.log(rest.length); // 2

객체에서 

let options = {
  title: "Menu",
  width: 100,
  height: 200
};

let {title, width, height} = options;

console.log(title);  // Menu
console.log(width);  // 100
console.log(height); // 200

객체도 rest를 이용할 수 있다. 

let options = {
  title: "Menu",
  width: 100,
  height: 200
};

let {title, ...rest} = options; //title = 이름이 title인 프로퍼티 rest = 나머지 프로퍼티들

// title엔 "Menu", rest엔 {height: 200, width: 100}이 할당됩니다.
console.log(rest.height);  // 200
console.log(rest.width);   // 100
Comments