[JS]자바스크립트 기초

코린이의 성장일기·2023년 8월 27일

대입 연산자

  • 대입연산자란 우항의 값을 좌항의 값으로 대입하기 위한 연산자
  • (수학) 에서 배우는 같다의 의미가 아니다
const point = 1
const arr = []
const myObject = {}
const yourObject = myObject

원시타입 vs 객체타입

  • 원시타입: 단일한 값을 담을 수 있는 타입
    • 예시) 다음과 같은 숫자, 문자열, boolean, null, undefined 등

      const num = 2
      const str = "자바스크립트"
      const isFemail = true
      const type = null
      
      const str2 = str
    • 특징

      • 변수 선언시 변수에는 값이 담기게 된다.
      • 다른 변수에 대입시 값에 의한 복사가 일어난다. (call by value)
  • 객체타입: 연관된 데이터를 담을 수 있는 타입
    • 예시) 다음과 같은 object, array, function 등

      const obj = {a: 1, b: 2}
      const arr = [1, 2, 3, 4, 5, 6]
      const func = () => {
        console.log('function call')
      }
      
      const arr2 = arr
    • 특징

      • 변수 선언시 변수에는 객체의 값이 담긴 메모리의 주소가 저장된다.
      • 다른 변수에 대입 시 주소에 의한 복사가 일어난다. (call by reference)

원시타입의 변수를 대입하는 경우 일어나는 일

// call by value
let myScore = 80
let yourScore = myScore

console.log(myScore)         // 80
console.log(yourScore)       // 80

myScore = 100

console.log(myScore)         // 100
console.log(yourScore)       // 80
  • Step 1) 주소공간 0x18 공간의 메모리에 80의 값이 저장된다.

Screenshot 2023-06-13 at 12.27.41 AM.png

  • Step 2) 메모리 공간중 빈공간을 찾아 yourScore 변수 할당하고 myScore의 값을 복사
    let yourScore = myScore

Screenshot 2023-06-13 at 12.28.09 AM.png

  • Step 3) myScore에 해당하는 메모리 공간의 값을 100으로 변경
    myScore = 100
    
    console.log(myScore)   =>  100
    console.log(yourScore) =>  80

Screenshot 2023-06-13 at 12.28.25 AM.png

객체타입의 변수를 대입하는 경우 일어나는 일

// call by reference
let order = [1, 2, 3, 4, 5]
let anotherOrder = order

console.log(order)         // [1, 2, 3, 4, 5]
console.log(anotherOrder)  // [1, 2, 3, 4, 5]

anotherOrder[0] = 5

console.log(order)         // [5, 2, 3, 4, 5]
console.log(anotherOrder)  // [5, 2, 3, 4, 5]
  • Step 1) 주소공간 0x22 공간의 메모리에 배열 [1, 2, 3, 4, 5] 가 저장된 힙 메모리의 주소가 저장된다. Screenshot 2023-06-13 at 12.54.18 AM.png
  • Step 2) 메모리 공간중 빈공간을 찾아 anotherOrder 변수 할당하고 order의 값 (힙 메모리 주소) 복사
    let anotherOrder = order
    Screenshot 2023-06-13 at 12.57.45 AM.png
  • Step 3) anotherOrder 로 접근한 힙 메모리 배열 객체의 첫번째 인덱스 값을 5로 변경
    anotherOrder[0] = 5
    Screenshot 2023-06-13 at 12.59.22 AM.png
  • 즉, 원시타입은 값에 의한 복사가 일어나고 객체 타입은 주소에 의한 복사가 일어난다.
  • shallow copy (얕은 복사) 문제는 바로 이와 같은 이유 때문에 발생

메모리 공간, 스택&힙

메모리 구조

  • 하나의 프로그램이 실행되기 위해선 메모리에 관련 데이터들이 로드되어야 합니다.
  • 메모리 공간은 영역별로 구분되어 있고 각 영역별로 역할이 다릅니다.
  • 메모리 공간은 다음과 같이 시각화 할 수 있습니다. (코드, 데이터, 힙, 스택 영역 구분) Screenshot 2023-06-13 at 12.23.37 PM.png
  • 각 영역 별로 어떤 일을 하는지 알아봅시다

코드 영역

  • 실행할 프로그램의 코드가 저장되는 영역
  • 즉, 컴퓨터가 이해할 수 있는 바이너리 코드가 저장되는 영역
  • CPU (정확히는 PC 레지스터)가 참조하여 프로그램을 실행할때 사용 Screenshot 2023-06-13 at 2.35.37 PM.png

데이터 영역

  • 프로그램의 전역 변수, 정적 변수가 저장되는 공간
  • 프로그램 시작 시 할당되고 종료 시 해제되는 특징
  • 전역 변수를 많이 사용하면 나쁜 이유?? (유추해보세요)
    • (장점): 편하다

    • (단점): 메모리가 부족할수 있다

      Screenshot 2023-06-13 at 2.41.50 PM.png

힙(Heap) 영역

  • 사용자(프로그래머) 에 의해 관리되는 영역
  • 즉, 프로그래머가 할당/해제하는 메모리 공간
  • 런타임시에 크기가 결정된다.
  • 예시) 객체 타입 - 클래스, object, array 등 Screenshot 2023-06-13 at 2.45.24 PM.png

스택(Stack) 영역

  • 프로그램이 자동으로 사용하는 임시 메모리 영역
  • LIFO (Last In First Out) 의 특징
  • 함수 호출이 완료되면 할당된 영역이 해제됩니다.
  • ex) 함수, 지역 변수 선언시 할당 1_muqsG1SNV6PjR6d4XFD_Mg.gif

함수 (Function)

함수의 정의

  • 특정한 목적을 수행하기 위해 설계된 블록
  • y = f(x)
  • Input (입력)으로 x를 넣으면 특정한 작업을 수행한 후 y(출력)를 반환한다.
  • 즉, 함수에게 일을 시킬때(함수 호출) 함수에게 알려줘야 하는 값 (매개변수)이 있고 함수는 특정 목적의 작업을 실행 후 결과를 반환한다.

Screenshot 2023-06-13 at 3.49.20 PM.png

함수 선언(Function Declaration) vs 함수 호출 (Function call)

  • 함수 선언 (Function Declaration)
    • 함수의 원형 (prototype)을 만든다는 뜻

    • 즉, 함수를 사용하기 위해 내용을 정의하는 행동

      function sumNumber(a, b) {
      	return a + b
      }
      
      const multiplyNumber = (a, b) => {
      	return a * b
      }
  • 함수 호출 (Function call)
    • 선언된 함수를 실제로 사용하는 행동

      sumNumber(1, 2) // => 3
      multiplyNumber(3, 4) // => 12

기명 함수 vs 익명 함수

  • 기명 함수 ⇒ 이름이 있는 함수
    function sumNumber(a, b) {
    	return a + b
    }
    
    function getMovieData(searchWord) {
      .....
    }
  • 익명 함수 ⇒ 이름이 없는 함수
    const multiplyNumber = (a, b) => {
    	return a * b
    }
    
    arr.filter(**() => {
    	....
    }**);
    
    const squareNum = function(num) {
    	return num * num
    }
  • 보통 기명 함수 ⇒ 함수 선언식
  • 익명 함수 ⇒ 함수 표현식 이라 합니다.
  • 둘은 어떤 차이가 있는 것일까?..

함수 선언식 vs 함수 표현식

  • 가장 큰 차이점은 호출되는 시점의 호이스팅 여부

함수 선언식

  • 함수 선언식의 형태
    function sumNumber(a, b) {
    	return a + b
    }
    
    function getMovieData(searchWord) {
      .....
    }
  • 호이스팅의 영향을 받아 함수 선언부가 스코프의 시작점으로 끌어 올려지는 현상 발생
    func()            // console.log 출력 됨
    
    function func() {
    	console.log('func function call!!!!')
    }

함수 표현식

  • 함수 표현식의 형태
    const multiplyNumber = (a, b) => {
    	return a * b
    }
    
    const squareNum = function(num) {
    	return num * num
    }
  • 호이스팅의 영향을 받지 않아서 함수 선언전에 함수 호출을 할 수 없음.
    func()   // 에러 발생 (ReferenceError: Cannot access 'func' before initialization)
    
    const func = () => {
    	console.log('func function call!!!!')
    }

호이스팅 (Hoisting)

변수의 생성 절차

  • (Step 1) : 실행 컨텍스트 등록 단계
    • 스코프의 실행 컨텍스트에 해당 변수를 등록한다.
  • (Step 2): 초기화 단계
    let num = 1

Screenshot 2023-06-13 at 4.56.09 PM.png

  • (Step 3): 할당 단계
    let num = 1

Screenshot 2023-06-13 at 4.56.31 PM.png

호이스팅의 정의

  • 코드 실행전 변수/함수 선언을 스코프의 최상단으로 끌어올리는 현상 (선언이 끌어올려지는 것임)

호이스팅의 동작 (함수)

  • 함수 선언식의 경우 함수 선언 자체가 스코프 위로 끌어 올려져 func 실행이 가능
    // case 1
    func()            // console.log 출력 됨
    
    function func() {
    	console.log('func function call!!!!')
    }
  • 함수 표현식의 경우 호이스팅이 일어나긴하지만 Step 1의 상태에서 일어나기 때문에 func 함수 호출시 에러 발생
    //case 2
    func()   // 에러 발생 (ReferenceError: Cannot access 'func' before initialization)
    
    let func = () => {
    	console.log('func function call!!!!')
    }
    
    // Step 2 (메모리에 공간을 할당받고 undefined) 
    let func = undefined
    
    // Step 3 func에 함수를 할당
    func = () => {
    	console.log('func function call!!!!')
    }

호이스팅의 동작 (변수)

  • var 키워드로 변수를 선언한 경우
    • var 키워드로 변수를 선언하면 (Step 1) 실행 컨텍스트 등록 + (Step 2) 초기화까지 실행된 상태로 호이스팅 됩니다.
      function func() {
      	console.log(num)   // undefined 출력
      
      	var num = 1
      }
      
      func()
      • 메모리에 초기화 된 상태로 호이스팅 되어 undefined로 출력
    • 스코프는 함수 스코프를 갖게 됩니다.
      function func() {
      		const num = 1
      		
      		if (num === 1) {
      				var hoistingVar = '호이스팅 잘되나요?'
      		}
      
      		console.log(hoistingVar) // 호이스팅 잘되나요? 출력
      }
      
      func()
  • let, const 키워드로 변수를 선언한 경우
    • let 키워드로 선언하면 (Step 1) 실행 컨텍스트 등록 상태까지만 진행되고 호이스팅 됩니다.
      function func() {
      	console.log(num)   // ReferenceError: Cannot access 'num' before initialization
      
      	let num = 1
      }
      
      func()
      • 메모리에 아직 올라가지도 못한 상태이기 때문에 ReferenceError 발생
    • 스코프는 블록 스코프를 갖게 됩니다.
      function func() {
      		const num = 1
      		
      		if (num === 1) {
      				let hoistingVar = '호이스팅 잘되나요?'
      		}
      
      		console.log(hoistingVar) // ReferenceError: hoistingVar is not defined
      }
      
      func()

스코프란?

스코프의 정의

  • 실행 컨텍스트에서 변수에 접근할 수 있는 scope(범위)를 뜻함

함수 스코프 vs 블록 스코프

  • 함수 스코프
    • var 키워드로 선언한 변수가 함수 스코프에 해당
    • 변수가 호이스팅 되는 시작점의 기준이 가장 가까운 함수가 됨
      function func1() {
      	**// (1)**
      	function func2() {
      		**// (2)**
      		const num = 1
      		
      		if (num === 1) {
      				**// (3)**
      				var hoistingVar = '호이스팅 잘되나요?'  // 어디까지 끌어 올려질까요?
      		}
      
      		console.log(hoistingVar)
      	}
      }
      
      func1()
  • 블록 스코프
    • let, const 키워드로 선언한 변수가 블록 스코프에 해당
    • 변수가 호이스팅 되는 시작점의 기준이 가장 가까운 블록이 됨
    • 블록은 중괄호 {} 로 열고 닫는 영역의 범위
      function func1() {
      	**// (1)**
      	function func2() {
      		**// (2)**
      		const num = 1
      		
      		if (num === 1) {
      				**// (3)**
      				let hoistingVar = '호이스팅 잘되나요?'  // 어디까지 끌어 올려질까요?
      		}
      
      		console.log(hoistingVar)
      	}
      }
      
      func1()

클로저

클로저의 정의 (링크)

  • (MDN) 함수와 함수가 선언된 어휘적 환경의 조합
  • (생활코딩) 내부함수가 외부함수의 맥락(context)에 접근할 수 있는 것
  • 내부함수에서는 외부함수 스코프에서 선언된 변수에 접근 기능하다.

클로저 예시

function init() {
    var name = "Mozilla"; // name은 init에 의해 생성된 지역 변수이다.

    function displayName() { // displayName() 은 내부 함수이며, 클로저다.
      alert(name); // 부모 함수에서 선언된 변수를 사용한다.
    }

    displayName();
}

init();
profile
작동하는 코드만 만들면 반은 완성이다.

0개의 댓글