Modern JS Deep Dive 1 - 16

MM·2022년 10월 19일

JSDeepDive

목록 보기
1/6
post-thumbnail

📃 1장 & 2장

🔹 JS는..

🔸 인터프리터 언어

컴파일러가 필요 없다!

한 줄 씩 바이트코드로 변환된 후 실행된다.
컴파일러 언어에 비해 속도가 느리고 실행파일을 별도로 생성하지 않는다.

🔸 멀티 패러다임 프로그래밍 언어

  • 명령형
  • 함수형
  • 프로토타입 기반
    클래스의 개념이 없고 기존 객체(prototype)를 복사하여 새로운 객체를 생성한다.



    따라서 모든 객체는 원형 객체를 참조하는 prototype 속성을 가지고 있다




📃 3장. JS 개발환경과 실행방법

🔹 브라우저와 노드

🔸 브라우저

  • 보안상의 문제로 파일 시스템을 제공하지 않는다
  • DOM 트리를 제공한다
  • 클라이언트 사이드 Wep API를 제공한다

🔸 Node

  • 파일 시스템을 제공한다
  • 시각화의 필요성이 없으므로 DOM 트리를 제공하지 않는다



📃 4장. 변수

🔹 예약어 vs 키워드

간단하게 말하면, 키워드는 예약어의 소집합이다!

🔸 예약어

const, goto..

js 시스템에서 먼저 사용하는 단어

🔸 키워드

int ,class

의미에 따른 룰이 있는 예약어

🔹 변수 선언

변수 선언은 런타임 이전 단계에서 실행된다. 이를 호이스팅이라고 표현한다.

🔸 JS 엔진의 변수 선언 단계

  • 선언 단계
  • 초기화 단계

🤠 var 선언

선언과 초기화 단계가 암묵적으로 함께 일어난다..

👉 80과 undefined는 가비지 콜렉터에 의해 정리된다. (언제 정리될지는 예측x)

🔸 실행 컨텍스트(execution context)

js 엔진이 소스코드를 실행하기 위해 필요한 환경을 제공하고 실행 결과를 관리하는 영역
식별자와 스코프가 이곳에서 관리된다

🔹 값 할당

값 할당은 런타임 시점에 발생한다.

🔸 가비지 콜렉터

애플리케이션이 할당한 메모리 공간을 주기적으로 검사하여 더 이상 사용되지 않는 메모리를 해제, 메모리 누수를 방지하는 기능

🧐 매니지드 언어와 언매니지드 언어

개발자가 메모리 직접 제어로 할당과 해제가 가능하면 언매니지드 언어, 불가능하면 매니지드 언어라고 한다.
JS는 직접적인 메모리 제어를 허용하지 않는 매니지드 언어다.




📃 5장. 표현식과 문

🔹 리터럴

사람이 이해할 수 있는 문자 또는 기호를 사용해 값을 생성하는 표기법

🔹 자체 종결성

코드 블록 등은 세미콜론을 붙이지 않아도 문의 종료를 의미하는 자체 종결성을 가진다.




📃 6장. 데이터 타입

🔹 원시 타입

Number, String, Boolean, undefined, null, symbol

🔸 Number

  • Infinity: 양의 무한대를 뜻하는 상수값
  • NaN: not a number (산술연산불가)

🔸 String

let string_1 = "string";
let string_2 = "string"; 

string_1===string_2; //true. 둘은 같은 메모리 주소를 가리킨다.

😬 템플릿 리터럴

백틱(``)을 이용한 string 표현법

😏 null과 indefined의 차이

undefined는 "아직 정의되지 않은 값"
null은 "의도적인 부재. 빈 값으로 정의된 값"

🔸 symbol

겹치지 않는 값을 만들기 위해 사용 (출력x 변환x)

Symbol(‘인자’): 인자는 해당 symbol의 설명description. symbol 영향x
Symbol.for(‘키값’): 레지스트리에서 해당 키값인 심볼 가져옴
Symbol.keyFor(‘심볼명’): 레지스트리에서 해당 심볼의 키값 가져옴

🔹 객체 타입

객체, 함수, 배열 등




7장 생략. 쓸 게 없다..




📃 8장. 제어문

🔹 switch

🔸 fall through

각 case문에서 break가 없어 해당 case를 거친 후 재할당되는 현상

🔹 레이블 문

식별자가 붙은 문. break를 사용 가능

foo: {
  console.log("foo");
  break foo;
}



📃 9장. 타입 변환과 단축 평가

🔹 암묵적 타입 변환

기존 변수 값의 재할당 ❌
표현식을 에러 없이 평가하기 위해 암묵적 타입 변환 값을 만들어서 한번만 쓰고 버림 ⭕

🔸 string으로 변환

어떠한 값 + "" = 모두 string으로 변환

🔸 number로 변환

  • number -*/> 어떠한 값 = 모두 number or NaN로 변환
  • +어떠한 값 = 모두 number or NaN(undefined)로 변환

🔹 단축 평가

🔸 단축 평가를 이용한 타입 안전성 검증

let foo=null;

console.log(foo.value) //error
console.log(foo && foo.value) //null로 정상작동

🔹 옵셔널 체이닝

let foo=null;
console.log(foo && foo?.value) //undefined로 정상작동

🔹 null 병합 연산자

let foo=null; //or undefined

console.log(foo ?? "foo는 null이므로 대신 이쪽을 출력한다");



📃 10장. 객체 리터럴

원시 타입 값은 변경 불가능하지만. 객체 타입 값은 변경이 가능하다

🔹 객체 리터럴 표현법

객체 리터럴에서의 대괄호는 코드 블록이 아니므로 세미콜론을 생략할 수 없다.

const 객체 = {0개 이상의 속성};

🔸 프로퍼티 삭제

delete person.name;



📃 11장. 원시 값과 객체의 비교

🔹 원시값

🔸 immutable(변경 불가능)

값이 수정될 때마다 해당 메모리를 수정하는 것이 아닌, 새로운 메모리에 할당된다!
상태 변경을 추적하기 쉬움
데이터 신뢰성 보장

let test="test";
test[0]="T";
console.log(test) //test

🔸 변수 할당과 복사

  • 변수 할당시 실제 값이 저장됨
  • 변수 복사시 새 메모리에 실제값 전달 (깊은 복사)

🔹 객체

🔸 변수 할당과 복사

  • 변수에 참조 값(메모리주소)이 저장됨
  • 변수 복사시 기존 메모리의 참조값(메모리주소) 전달 (얕은 복사)




📃 12장. 함수

🔹 함수 정의

🔸 함수 선언문

function add(x,y){ return x+y; } //단독 사용시 함수 선언문
(function add(x,y){return x+y;}) //피연산자로 사용시 함수 리터럴 👉 함수 식별자 없음
  • js가 암묵적으로 함수이름을 함수 식별자로 할당 👉 함수 이름 생략 불가
  • 런타임 이전에 함수 객체 생성하여 함수 호이스팅 가능

🤨 함수 이름과 함수 식별자의 차이

const 함수 식별자 = function 함수 이름() {};
함수식별자(); //⭕
함수이름();   //❌

😕 함수 호이스팅을 피해라

함수 호이스팅은 함수를 호출하기 전에 반드시 함수를 선언해야 한다는 규칙을 무시한다.
함수 선언문 대신 함수 표현식을 사용하자!

🔸 함수 표현식

const add = function(x,y){return x+y;};
  • 변수만 호이스팅되고 함수 할당은 나중에 되므로 호이스팅 불가

🔸 function 생성자 함수

const add=new Function('x','y','return x+y');
  • 클로저를 생성하지 않는다

🔸 화살표 함수

const add=(x,y)=>{return x+y;};

모든 화살표 함수는 익명 함수이다 (식별자O 이름X)
기존 함수와 달리 객체가 생성될 때 this를 재정의해준다
*prototype 프로퍼티가 없다

🔹 일급객체(first-class object)

자바스크립트의 모든 객체는 일급객체!

🔸 일급객체의 정의

값을 가지고 있는 객체!

🔸 일급객체의 조건

  • 익명 리터럴로 생성 가능 -> 런타임 때 동적 생성가능
  • 변수나 자료구조, 다른 객체에 저장이 가능함
  • 객체가 다른 함수에 인자로 전달될 수 있음
  • 함수 리턴값으로 사용 가능

🔹 매개변수

🔸 인수 < 매개변수

남은 매개변수는 undefined 처리된다

🔸 인수 > 매개변수

남은 인수는 함수의 arguments 객체에 프로퍼티로 보관된다.
console.log(arguments)를 하면 볼 수 있다.

🔹 반환문

🔸 반환문이 없으면..

암묵적으로 undefined가 return된다

🔹 즉시 실현 함수 (IIFE)

Immediately invoked function expression

(function() {...}());
  • 함수 선언과 동시에 호출되는 함수 (재사용x)
    • 주로 익명 함수를 ()로 감싸서 사용
    • 연산자만 붙으면 IIFE로 사용 가능하다
  • 전역변수를 최소화시켜 스코프간 변수 충돌 방지
    👉 라이브러리 등에서 자주 사용

🔹 콜백함수와 고차함수

🔸 콜백함수(callback)

다른 함수의 인자로써 넘겨진 후 특정 이벤트에 의해 호출되는 함수.

🔸 고차함수(high-ordered)

콜백함수를 파라미터로 받아 사용하는 함수.
함수를 인자로 전달받거나 함수를 결과로 반환한다.
👉 고차함수는 콜백함수를 자신의 일부분으로 합성한다.

😀 어디에 사용하나요?

원래 있는 함수를 수정할 때 기존에 사용하던 함수를 곧바로 수정하는 것은 위험!
따라서 콜백함수를 별도로 만들어 인자로 넘기는 방식을 채택한다.

eventListener에서 onClick에 함수를 넣어주는 것도 고차함수의 일종이다!

이외에도 배열 고차 함수(filter, map..) 등에서도 사용된다!

🔹 순수 함수와 비순수 함수

let cnt=0;

function 순수함수(cnt){ return cnt+1; } //어떤 상황에서도 cnt+1을 return.
function 비순수함수(){ return cnt+1;} //cnt의 상태에 따라 다른 값을 return.

🔸 순수 함수

  • 외부상태에 의존하지 않고 부수 효과를 가지지 않는 함수
  • 동일한 인수에 동일한 값을 return한다
    • 불변성을 지향한다
  • 함수형 프로그래밍에 주로 사용된다

🔸 비순수 함수

  • 외부상태에 의존하거나 외부상태를 변경하는, 부수효과가 있는 함수
  • 외부 상태에 따라 같은 인수여도 다른 값을 return한다
    • 상태 변화를 추적하기 어렵다



📃 13장. 스코프

🔹 식별자 결정

중첩된 스코프 내에서 같은 이름의 식별자가 있을 때,
둘 중 어떤 것을 사용할 지 JS엔진이 고르는 행위를 말한다.

🔹 동적 스코프와 정적 스코프

JS는 정적 스코프!

동적(dynamic) 스코프는 함수가 호출된 곳을 기준으로 결정된다.
정적(lexical) 스코프는 함수가 정의된 곳을 기준으로 결정된다.

var x=1;

function foo(){
  var x=10;
  boo(); //함수호출 x=10
}

function boo(){ //함수 정의 x=1
  console.log(x);
}

foo();
// 동적 스코프에서는 호출된 곳의 로컬스코프를 우선하므로 x=10.
// 정적 스코프에서는 정의된 곳의 로컬스코프를 우선 찾으므로 x=1.

🔹 함수 레벨 스코프와 블록 레벨 스코프

JS는 함수 레벨 스코프!

블록 레벨 스코프는 같은 블록인 것이 중요하고, 👉 let, const
함수 레벨 스코프는 같은 함수인 것이 중요하다. 👉 var

var global="전역";

if(global=="전역"){
	var global="지역"
    console.log(global); //지역
}

console.log(global);
//블록 레벨 스코프에서는 지역 블록이 끝났으므로 "전역"
//함수 레벨 스코프에서는 아직 같은 함수 내므로 "지역"

🤭 Lexical environment

코드가 어디에서 실행되고 주위에 어떤 코드가 있는가 👉 코드 문맥을 구성하는 환경

🤗 execution context(실행 컨텍스트)

lexical environment를 구현한 것

🔹 scope chain

실행 컨텍스트의 랙시컬 환경을 단방향으로 연결한 것
변수를 찾을 때 로컬 스코프에서 찾을 수 없다면 한 단계 상위 스코프로 올라가 찾는다.

function scope1(){
  var x=1;
 function scope2(){
   var x=10; //찾았으므로 더이상 체인을 타고 위로 올라가지 않는다.
   function scope3(){
     console.log(x);
   }
 }
}



📃 14장. 전역 변수의 문제점

🔹 변수의 생명주기

var x = 'global'; //외부 var 할당

function foo(){
  console.log(x); // undefined 👉 내부 var 호이스팅
  var x = 'local'; // 내부 var 할당
}

foo();
console.log(x); //global 👉 외부 var 호이스팅

🔹 암묵적 결합

모든 코드가 전역 변수를 참조하고 변경할 수 있는 상태

🔸 전역 변수의 단점

  • 스코프 체인 상에서 종점에 존재하여, 검색 속도가 느리다
  • 가독성이 나쁘다
  • 메모리 자원을 소모하므로 자원 사이클이 원활하게 돌아가지 않는다
  • 다른 파일들과 변수 충돌 여지가 존재한다



📃 15장. let, const 키워드와 블록레벨 스코프

🔹 var의 문제점

🔸 중복 선언 가능

var x=1;
var x=2; //가능. 에러 없음!

🔸 함수 레벨 스코프

함수 외부에서 선언한 변수는 코드 블록 내에서 선언시 모두 전역 변수가 된다.

var x=1;
if(1){var x=10;}
console.log(x); //10

🔸 호이스팅

var은 변수 선언(메모리 할당)과 초기화(undefined)가 동시에 발생하기 때문에,
변수 호이스팅에 의해 var이 값 할당 전에 함수의 최상단으로 끌어올려진다.

console.log(x); //undefined
var x=1;

🔸 전역 var은 암묵적으로 window 객체의 프로퍼티

var x=1;
console.log(window.x); //1

🔹 let은 이렇게 고쳤습니다

🔸 중복 선언 불가능

let x=1;
let x=2; //불가능. 에러발생!

🔸 블록 레벨 스코프

let x=1;
if(1){let x=10;}
console.log(x); //1

🔸 호이스팅이 일어나지 않는 것처럼 보인다

let은 선언(메모리 할당)과 초기화(undefined)가 동시에 일어나지 않는다.
따라서 선언(메모리 할당)만 된 시점에서는 호이스팅되어도 변수 사용이 불가능하다.
👉 호이스팅이 안 되는 것처럼 동작!

console.log(x); //에러발생
let x=1;

😐 템퍼럴 데드 존(TDZ)

let a=1;   	//첫번째 a 호이스팅
if(1){
  //템퍼럴 데드 존: 두번째 a 호이스팅 but 값 미정 = 변수사용x 구간
  console.log(a);
  let a=100;        //두번째 a 호이스팅
}

🔸 전역 let은 window의 프로퍼티 아님!

let x=1;
console.log(window.x); //undefined



📃 16장. 프로퍼티 어트리뷰트

🔹 내부 슬롯과 내부 메서드

🔸 내부 슬롯 [[ ]]

js 엔진 내부 로직이므로 직접 접근이 불가능하다.

[[Prototype]]

모든 객체는 해당 내부 슬롯을 가진다.
._ _ proto __ 를 통해 접근 가능하다.

🔸 내부 메서드

🔹 프로퍼티

JS 엔진은 프로퍼티를 생성할 때 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의한다!

🔸 데이터 프로퍼티와 접근자 프로퍼티

const person={
	//데이터 프로퍼티
  	firstName: '홍',
  	lastName: '길동',
  
    //접근자 프로퍼티
    get fullName(){ return firstName+lastName; }
    set fullName(name){ [this.firstName, this.lastName]=name.split(' '); }
}

🥦 데이터 프로퍼티

일반 객체의 _ _proto__

키와 값으로 구성된 일반적인 프로퍼티.
Object.defineProperty(객체타입, 프로퍼티명, {프로퍼티 목록})으로 정의 가능하다.

  • [[Value]]: property의 값
  • [[Writable]]: property 값 수정가능 여부
  • [[Enumerable]]: property 열거 가능 여부 (for문 사용 가능 여부)
  • [[Configurable]]: property attribute 재정의 가능 여부

🥕 접근자 프로퍼티

함수 객체의 prototype

자체적으로 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 호출되는 접근자 함수로 구성된 프로퍼티

  • [[Get]]: 접근자 프로퍼티를 통해 데이터 프로퍼티 값을 읽을 때 호출되는 접근자 함수
  • [[Set]]: 접근자 프로퍼티를 통해 데이터 프로퍼티 값을 저장할 때 호출되는 접근자 함수
  • [[Enumerable]]
  • [[Configurable]]

😮 프로토타입

어떤 객체의 부모 객체로 하위 객체에게 자신의 프로퍼티와 메서드를 상속한다!

😍 프로토타입 체인

프로토타입이 단방향 링크드리스트형태로 연결된 상속 구조.
현재 객체에 찾는 프로퍼티나 메소드가 없다면, 프로토타입 체인을 따라 올라가며 프로퍼티나 메서드를 찾는다~

🔹 객체 변경 방지

JS에서 제공하는 객체 변경 방지 메서드 목록

🔸 Object.preventExtensions(변수명)

객체 확장 금지(프로퍼티 추가 금지) 메서드

🔸 Object.seal(변수명)

프로퍼티 추가, 삭제, 재정의 금지
👉 객체 읽기, 쓰기만 가능!

🔸 object.freeze(변수명)

객체 동결
👉 객체 읽기만 가능!
👉 단, 중첩된 객체에서 내부 객체까지 동결되진 않는다!

profile
중요한 건 꺾여도 그냥 하는 마음

0개의 댓글