내일배움캠프 React_7기 TIL - 8.javascript 문법 종합반 3주차 + 최소직사각형 알고리즘

·2024년 10월 11일
1
post-thumbnail

변수의 데이터 저장 원리

let str;
str = 'test'

값을 바로 변수에 대입하지 않는 이유? → 자유로운 데이터 변환, 메모리의 효율적 관리를 위함. (자리 이동 최소화)

이름 : str 데이터 : @5004 ?

이렇게 저장되어있는 것이 아니고
코드와 사용자는 var str은 @1002 를 말하는 거라고 그냥 쓰는것일 뿐..
실제 공간에는 주소값만 있음. 변수명은 코드 내에서의 식별자일 뿐 저장X

1. 변수 vs 상수 (메모리 관점)

  • 변수: 변수가 차지하는 메모리 공간은 값을 변경할 수 있습니다.
    • 참조: 변수는 데이터(값)가 저장된 메모리 주소를 참조할 수 있고, 이 주소를 변경해서 다른 값을 가리킬 수도 있습니다.
  • 상수: 상수는 선언 후 값을 변경할 수 없으며, 상수가 참조하는 데이터의 주소나 그 값을 변경할 수 없습니다.
    • 참조 불가: 상수는 메모리에서 읽기 전용 영역에 저장되고, 값을 변경하려고 하면 에러가 발생합니다. 예를 들어 const int y = 10;이라면, y = 20;은 불가능합니다.

2. 불변성 (데이터 영역 관점)

  • 불변하다: 데이터 영역에서 값이 한 번 할당되면 변경할 수 없는 경우입니다.
    • 예를 들어 문자열 같은 불변 객체는 데이터가 변경될 때마다 새로운 메모리 공간에 복사됩니다. JavaScript의 문자열이 대표적인 예로, 문자열을 수정하면 새로운 메모리 공간에 수정된 값이 저장됩니다.
  • 불변하지 않다: 데이터 영역에서 값을 자유롭게 변경할 수 있는 경우입니다.
    • 예를 들어, 배열이나 객체 같은 참조형 데이터는 참조하는 메모리 주소의 값을 직접 수정할 수 있습니다. 단, 해당 참조 자체는 상수일 수 있습니다.

요약하면:

  • 변수는 을 변경할 수 있고, 변수 공간은 다른 값을 참조할 수 있습니다.
  • 상수는 을 변경할 수 없으며, 참조하는 메모리나 값 자체를 변경할 수 없습니다.
  • 불변성은 메모리 공간에서 값을 변경할 수 있는지 여부를 말하며, 데이터의 성격에 따라 다릅니다.

상수는 '값 자체'와 '참조' 모두 변경할 수 없다는 점에서 제한이 있고, 변수는 '값'을 자유롭게 변경할 수 있다

그럼 안 쓰게 된 데이터는 어디로 가냐 ? → 가비지 컬렉터가 더이상 참조되지 않는 공간을 탐색하여 삭제함

obj1을 복사한 obj2의 원소를 변경하면 → obj도 똑같은 주소를 바라보고 있기에 obj1까지 변경된다

그렇기에, 가변하는 객체의 복사는 주의해야한다.

그래서 객체의 프로퍼티에 접근해서 값을 변경하지 말고 객체 자체를 변경하면 obj1과 obj2는 다른 공간을 바라보기에 서로 독립적이 된다.

  • 헷갈리는 점 찾아봄
    1. 변수 영역? 데이터 영역?
      1. 그…런게 있었다고? 싶어서 찾아보니 변수 영역 데이터 영역 이런거 따로 없다.
        → 실제 메모리 상에서 물리적으로 나눠져 있지 않고, 메모리 할당 시 필요한 공간을 찾고 사용하는 것이 맞습니다. 변수나 데이터는 각각 필요한 메모리 공간에 저장되며, 운영체제가 자유롭게 메모리를 관리합니다. 그냥 이해하기 쉽도록 하신듯…?
    2. ‘데이터 영역에서 10이 있는지 찾습니다…’ 와 같은 내용
      1. var a = 1; var b=1;일 때, 1이 저장된 주소값을 a, b 둘 다 바라보고 있게 된다는 뜻?

        일리가 없을텐데…

        원시 타입(number, string, boolean 등)의 경우,
        동일한 값이라도 각각의 변수가 서로 다른 메모리 공간에 값을 저장한다.

실행 컨텍스트

실행 컨텍스트 : 실행할 코드에 제공할 환경 정보들을 모아놓은 객체

콜 스택

내가 코드를 짜면, 그걸 스택으로 쌓기 때문에 JS는 코드의 환경 및 순서를 보장?

→ 실행 컨텍스트 쉽게 말해서 실행 순서(흐름) 인듯. 내가 짜면 실행 순서에 따라 스택에 쌓이고 그걸 콜 스택이라고 부른다.

  1. 컨텍스트의 구성

    전역공간, eval()함수 등 컨텍스트를 구성하는 방법엔 여러가지가있긴한데?

    함수 ← 가 흔하게 실행 컨텍스트를 구성하는 방법.

    함수 실행 순서를 말하는듯?

    특정 실행 컨텍스트가 활성화되는 시점 == 스택의 최상단에 위치할 때

  1. 실행 컨텍스트에는 어떤 내용이 있는가

    크게 3가지 1. VariableEnvironment, 3. LexicalEncironment 3. ThisBinding

    • VariableEnvironment(VE)

      1. 현재 컨텍스트 내의 식별자 정보(=record)

        아까 변수명 자체가 식별자다! 라고 했으니까, var a 같은거

      2. 외부 환경 정보(Outer)

      3. 선언 시점 LexicalEncironment의 Snapshot

    • LexicalEncironment (LE)

      1. 구성요소는 VE와 동일하지만, 변경사항을 실시간으로 반영
    • ThisBinding

      1. this 객체가 바라봐야할 객체
💡 결국 실행 컨텍스트를 생성할 때, VE에 정보를 먼저 담은 다음, LE에 복사, 이후에는 LE활용

VE와 LE는 snapshot 유지 여부의 차이만 있다.

record → 호이스팅

식별자 정보를 수집할 때 호이스팅 개념이 나온다. 호이스팅은 가상 개념인 점 참고

호이스팅 : 식별자를 수집하고, 위로 끌어올린다.

함수 선언문, 함수명 a가 곧 변수명
function a() {...};

함수 표현식, func을 별도의 변수에 할당하는 경우. 
1. 익명함수표현식
var b = () => {...};

2. 기명함수표현식 (활용성 거의 x)
var c = function d() {...};

c(); <- 이건 실행
d(); <- 이건 에러

호이스팅 과정에서, 함수 선언문은 그 자체가 식별자이기 때문에 함수 자체가 위로 끌어올려지는 반면, 함수 표현식은 다른 변수와 같이 var b 만 끌어올려진다.

함수 선언식보다 함수 표현식을 사용하는게 동명의 함수 이슈 또는 실행 범위 문제에서 더 안전하다?

Outer

실행 컨텍스트에서 바로 이전 스택의 LexicalEnvironment가 현재 스택의 Outer가 된다.

즉, 이전 환경을 참조하게 된다. 이후의 환경(이후의 스택)은 참조할 수 없다. 상위 스코프에서만 참조할 수 있다는 원리

스코프 체이닝

스코프 체이닝(Scope Chaining):

  • 스코프 체이닝은 현재 스코프에서 변수를 찾을 수 없을 때, 상위 스코프(Outer Lexical Environment)로 올라가며 변수를 찾는 과정을 의미합니다. 이는 함수가 호출된 환경을 기준으로, 실행 컨텍스트가 쌓여가는 구조를 통해 이루어집니다.

각각의 실행 컨텍스트는 LE를 갖고 있고, LE에는 Record와 Outer을 가지고 있는데, LE는 현재 스코프의 LE(현재 스코프에 선언된 변수와 함수에 대한 정보), Outer은 상위 스코프의 LE를 참조한다.

this

this는 실행 컨텍스트가 생성될 때(=바인드 될 때) 결정된다.

(=함수를 호출할 때 결정된다)

전역 환경에서 this는 → node(global), 브라우저(window)

함수 vs 메서드

엄연한 차이가 존재! 독립성, 호출 주체가 O/X 로 나뉜다

함수는 그 자체로서 독립적인 기능을 하고 호출이 가능하지만

메서드는 자신을 호출한 대상 객체에 대한 동작을 수행하는 종속성이 있다.

그래서 …

함수는 this가 전역 객체 (호출의 주체를 명시할 수 없기 때문)

메서드는 this가 호출의 주체(메서드를 소유한 객체)가 된다.


내가 오해한 점

this는 상위 주체를 가르키는 건가? → X

무조건 상위 주체라고 하면 틀리고 “상황에 따라 다르다“ 라는 표현이 맞다고 함

전역 스코프에서 this → window(브라우저)

함수 내부에서 (엄격 모드가 아닐 때), 호출 주체가 없으면 this는 전역 객체(브라우저의 경우 window, Node.js에서는 global)

엄격 모드에서는 함수 내부에서 호출 주체가 없으면 thisundefined가 된다.

메소드에서는 호출한 주체 단, 메서드 내의 함수의 this는 전역객체


알고리즘 숙제

프로그래머스 - 최소 직사각형 문제


이것은 난리의 흔적...

아래는 오답 코드

function solution(sizes) {
  
    let maxCardSize = 0;
    let tempArr = [];

    //제일 큰 카드 사이즈 찾기
    for(const card of sizes){
        let cardSizes = card[0] * card[1];
        maxCardSize = (cardSizes > maxCardSize) ? cardSizes : maxCardSize;
    }
   
    for(let i =0; i<sizes.length;i++){
            for(let k =0; k<sizes.length;k++){
                let cardSize =sizes[i][0]*sizes[k][1];
                if(cardSize >= maxCardSize)
                tempArr.push(cardSize);
        }
    }

    return Math.min(...tempArr);
}

가장 큰 카드의 사이즈를 구하고, 이것보다 더 큰 크기가 나오는 조합 중 최소값을 찾으면 된다고 생각했는데 일부의 케이스에만 정답이 나오고 많은 케이스에서 오답... 이 나온 코드다.

아 풀다가 문제의 접근법이 틀려먹은 것 같아 결국 gpt에게 도움 요청

가로 세로 중 큰 값을 한 열로 모는 것이 포인트였다...
이 아이디어가 그렇게 생각이 안났다

가장 큰 값을 구하고... 그리고 그 큰 값이 있는 배열의 다른 원소보다 큰... <- 이러고 한참을 뻘짓했었다^^

이것은 통과한 코드 ^^v

function solution(sizes) {
    const Sorted = [];
    let maxWidth = 0;
    let maxHeight = 0;


    // 가장 긴 값을 한 열로 몰기
    for (const card of sizes) {
        if (card[1] > card[0]) {
          //구조분해할당 사용
            [card[0], card[1]] = [card[1], card[0]];
        }

        Sorted.push(card);
    }

    // Sorted.forEach(card => console.log(card)); // 각각의 배열 요소를 출력

    for(const card of Sorted){
        maxWidth = (card[0]>maxWidth)? card[0]:maxWidth;
        maxHeight = (card[1]>maxHeight)? card[1]:maxHeight;
    }

    return maxWidth*maxHeight

}

중간은 확인용 콘솔....
이렇게 간단하게 구현할 수 있는 문제였구나~

참고로 저번에 배운 구조분해할당(비구조화 할당) 써봤다. temp 써서 하려다가 다시 찾아보고 적용했다. ES6문법에 익숙해지도록 많이 써봐야지.

이번 문제는 gpt가 거의 풀어준거나 마찬가지라 약간 찝찝한 기분을 지울 수 없지만
앞으로 더 열심히 알고리즘 공부하는걸로...

profile
내배캠 React_7기 이수중

1개의 댓글

comment-user-thumbnail
2024년 10월 14일

gpt 사용하셨다고 해도 본인의 언어로 내용을 풀어 적어서 til 잘 작성해 주셨내요! 이렇게 계속 알고리즘이나 코드짜는 흐름을 배우는게 초반에는 정말 중요해서, 잘하고 있으십니다!(。・ω・。)

답글 달기

관련 채용 정보