모던 자바스크립트 딥다이브Chapter13~18

HYEON17·2022년 12월 31일
0

WIL

목록 보기
3/13
post-thumbnail

Chapter13 스코프

13.1 스코프란?

식별자가 유효한 범위

13.2 스코프의 종류

13.2.1 전역과 전역 스코프

지역변수는 자신의 지역 스코프와 하위 지역 스코프에서 유효

13.2.2 지역과 지역 스코프

지역 변수는 자신의 지역 스코프와 하위 지역 스코프에서 유효

13.3 스코프 체인

  • 스코프가 계층적으로 연결된 것
  • 변수를 참조할 때 자바스크립트 엔진은 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 시작하여 상위 스코프 방향으로 이동하며 선언된 변수를 검색한다
    • 이를 통해 상위 스코프에서 선언한 변수를 하위 스코프에서도 참조 가능

13.3.1 스코프 체인에 의한 변수 검색

상위 스코프에서 유효한 변수는 하위 스코프에서 자유롭게 참조할 수 있지만 하위 스코프에서 유효한 변수를 상위 스코프에서 참조할 수 없다

13.4 함수 레벨 스코프

  • var키워드로 선언된 변수는 오로지 함수의 코드블록(함수 몸체)만을 지역 스코프로 인정
var i = 10;

// for 문에서 선언한 i는 전역 변수다. 이미 선언된 전역 변수 i가 있으므로 중복 선언된다.
for (var i = 0; i < 5; i++) {
  console.log(i); // 0 1 2 3 4
}

// 의도치 않게 변수의 값이 변경되었다.
console.log(i); // 5
  • let, const 키워드는 블록 레벨 스코프를 지원

13.5 렉시컬 스코프

  • 자바스크립트는 렉시컬 스코프를 따르므로 함수를 어디서 정의했는지에 따라 상위 스코프를 결정
  • 함수가 호출된 위치는 상위 스코프 결정에 어떠한 영향도 주지 않음
    • 즉, 함수의 상위 스코프는 언제나 자신이 정의된 스코프이다

Chapter14 전역 변수의 문제점

14.1 변수의 생명 주기

14.1.1 지역 변수의 생명 주기

  • 지역변수의 생명주기는 함수의 생명 주기와 일치
  • 호이스팅은 스코프를 단위로 동작
    • 변수 선언이 스코프의 선두로 끌어 올려진 것처럼 동작

14.1.2 전역 변수의 생명 주기

var 키워드로 선언한 전역 변수의 생명주기는 전역 객체의 생명주기와 일치

14.2 전역 변수의 문제점

  • 암묵적 결합
    • 변수의 유효 범위가 클수록 코드의 가독성은 나빠지고 의도치 않게 상태가 변경될 수 있는 위험성도 높아진다
  • 긴 생명 주기
  • 스코프 체인 상에서 종점에 존재
  • 네임스페이스 오염
    • 다른 파일 내에서 동일한 이름에로 명명된 전역 변수나 전역 함수가 같은 스코프 내에 존재할 경우 예상치 못한 결과를 가져올 수 있다

14.3 전역 변수의 사용을 억제하는 방법

14.3.1 즉시 실행 함수

모든 코드를 즉시 실행 함수로 감싸면 모든 변수는 즉시 실행 함수의 지역 변수가 됨

(function () {
  var foo = 10; // 즉시 실행 함수의 지역 변수
  // ...
}());

console.log(foo); // ReferenceError: foo is not defined

14.3.3 모듈 패턴

  • 전역 변수의 억제는 물론 캡슐화까지 구현 가능
  • 정보 은닉을 구현하기 위해 사용

캡슐화

객체의 상태를 나타내는 프로퍼티와 프로퍼티를 참조하고 조작할 수 있는 동작인 메서드를 하나로 묶는것

  • 즉시 실행함수는 객체를 반환
var Counter = (function () {
  // private 변수
  var num = 0;

  // 외부로 공개할 데이터나 메서드를 프로퍼티로 추가한 객체를 반환한다.
  return {
    increase() {
      return ++num;
    },
    decrease() {
      return --num;
    }
  };
}());

// private 변수는 외부로 노출되지 않는다.
console.log(Counter.num); // undefined

console.log(Counter.increase()); // 1
console.log(Counter.increase()); // 2
console.log(Counter.decrease()); // 1
console.log(Counter.decrease()); // 0

Chapter15 let, const 키워드와 블록 레벨 스코프

15.1 var 키워드로 선언한 변수의 문제점

15.1.1 변수 중복 선언 허용

var키워드는 변수 중복을 허용한다

15.1.2 함수 레벨 스코프

  • var키워드로 선언한 변수는 오로지 함수의 코드 블록만을 지역 스코프로 인정함
  • 함수 외부에서 var키워드로 선언한 변수는 코드 블록 내에서 선언해도 모두 전역 변수가 됨
var x = 1;

if (true) {
  // x는 전역 변수다. 이미 선언된 전역 변수 x가 있으므로 x 변수는 중복 선언된다.
  // 이는 의도치 않게 변수값이 변경되는 부작용을 발생시킨다.
  var x = 10;
}

console.log(x); // 10

15.1.3 변수 호이스팅

var키워드로 변수를 선언하면 변수 호이스팅에 의해 변수 선언문이 스코프의 선두로 끌어 올려진 것처럼 동작

15.2 let 키워드

15.2.1 변수 중복 선언 금지

let키워드는 변수 중복을 허용하지 않는다

15.2.2 블록 레벨 스코프

let키워드로 선언한 변수는 모든 코드 블록을 지역 스코프로 인정하는 블록 레벨 스코프를 따른다

15.2.3 변수 호이스팅

let키워드로 선언한 변수는 선언 단계와 초기화 단계가 분리되어 진행

15.2.4 전역 객체와 let

let키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 아니다

15.3 const 키워드

15.3.1 선언과 초기화

const키워드로 선언한 변수는 반드시 선언과 동시에 초기화해야 한다

15.3.2 재할당 금지

var, let 키워드로 선언한 변수는 재할당이 자유로우나 const키워드는 재할당 금지

15.3.3 상수

상수는 재할당이 금지된 변수

15.3.4 const 키워드와 객체

  • const 키워드로 선언된 변수에 객체를 할당한 경우 값을 변경 가능
  • 재할당을 금지할 뿐 불변을 의미하지는 않음
    • 프로퍼티의 동적 생성, 삭제, 프로퍼티 값의 변경을 통해 객체를 변경하는 것은 가능

15.4 var vs. let vs. const

  • 재할당시 let사용
  • 변경 발생 없고 읽기전용으로 사용하는 원시 값과 객체에는 const를 사용
  • var는 사용을 안하는게 좋다

Chapter16 프로퍼티 어트리뷰트

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

데이터 프로퍼티

키와 값으로 구성된 일반적인 프로퍼티

접근자 프로퍼티

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

16.4 프로퍼티 정의

16.5 객체 변경 방지

16.5.1 객체 확장 금지

프로퍼티 추가 금지

16.5.2 객체 밀봉

읽기와 쓰기만 가능

16.5.3 객체 동결

읽기만 가능

Chapter17 생성자 함수에 의한 객체 생성

17.1 Object 생성자 함수

new 연산자와 함께 object 생성자 함수를 호출하면 빈 객체를 생성하여 반환

// 빈 객체의 생성
const person = new Object();

// 프로퍼티 추가
person.name = 'Lee';
person.sayHello = function () {
  console.log('Hi! My name is ' + this.name);
};

console.log(person); // {name: "Lee", sayHello: ƒ}
person.sayHello(); // Hi! My name is Lee

생성자 함수에 의해 생성된 객체를 인스턴스라고 한다

17.2 생성자 함수

17.2.1 객체 리터럴에 의한 객체 생성 방식의 문제점

직관적이고 간편하지만 단 하나의 객체만 생성한다는 단점이 존재

17.2.2 생성자 함수에 의한 객체 생성 방식의 장점

객체르 생성하기 위한 템플릿 처럼 생성자 함수를 사용하여 프로퍼티 구조가 동일한 객체 여러개를 간편하게 생성할 수 있다

// 생성자 함수
function Circle(radius) {
  // 생성자 함수 내부의 this는 생성자 함수가 생성할 인스턴스를 가리킨다.
  this.radius = radius;
  this.getDiameter = function () {
    return 2 * this.radius;
  };
}

// 인스턴스의 생성
const circle1 = new Circle(5);  // 반지름이 5인 Circle 객체를 생성
const circle2 = new Circle(10); // 반지름이 10인 Circle 객체를 생성

console.log(circle1.getDiameter()); // 10
console.log(circle2.getDiameter()); // 20

new연산자와 함께 생성자 함수를 호출하지 않으면 생성자 함수가 아니라 일반 함수로 동작

// new 연산자와 함께 호출하지 않으면 생성자 함수로 동작하지 않는다.
// 즉, 일반 함수로서 호출된다.
const circle3 = Circle(15);

// 일반 함수로서 호출된 Circle은 반환문이 없으므로 암묵적으로 undefined를 반환한다.
console.log(circle3); // undefined

// 일반 함수로서 호출된 Circle내의 this는 전역 객체를 가리킨다.
console.log(radius); // 15

17.2.3 생성자 함수의 인스턴스 생성 과정

  1. 인스턴스 생성과 this 바인딩
    인스턴스는 this에 바인딩 된다
function Circle(radius) {
  // 1. 암묵적으로 인스턴스가 생성되고 this에 바인딩된다.
  console.log(this); // Circle {}

  this.radius = radius;
  this.getDiameter = function () {
    return 2 * this.radius;
  };
}
  1. 인스턴스 초기화
    this에 바인딩 되어 있는 인스턴스에 프로퍼티나 메서드를 추가하고 생성자 함수가 인수로 전달받은 초기값을 인스턴스 프로퍼티에 할당하여 초기화하거나 고정값을 할당
function Circle(radius) {
  // 1. 암묵적으로 인스턴스가 생성되고 this에 바인딩된다.

  // 2. this에 바인딩되어 있는 인스턴스를 초기화한다.
  this.radius = radius;
  this.getDiameter = function () {
    return 2 * this.radius;
  };
}
  1. 인스턴스 반환
    생성자 함수 내부에서 모든 처리가 끝나면 완성된 인스턴스가 바인딩된 this를 암묵적으로 반환
function Circle(radius) {
  // 1. 암묵적으로 인스턴스가 생성되고 this에 바인딩된다.

  // 2. this에 바인딩되어 있는 인스턴스를 초기화한다.
  this.radius = radius;
  this.getDiameter = function () {
    return 2 * this.radius;
  };

  // 3. 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환된다
}

// 인스턴스 생성. Circle 생성자 함수는 암묵적으로 this를 반환한다.
const circle = new Circle(1);
console.log(circle); // Circle {radius: 1, getDiameter: ƒ}

this가 아닌 다른 객체를 명시적으로 반환하면 this가 반환되지 못하고 return문에 명시한 객체가 반환

function Circle(radius) {
  // 1. 암묵적으로 인스턴스가 생성되고 this에 바인딩된다.

  // 2. this에 바인딩되어 있는 인스턴스를 초기화한다.
  this.radius = radius;
  this.getDiameter = function () {
    return 2 * this.radius;
  };

  // 3. 암묵적으로 this를 반환한다.
  // 명시적으로 객체를 반환하면 암묵적인 this 반환이 무시된다.
  return {};
}

// 인스턴스 생성. Circle 생성자 함수는 명시적으로 반환한 객체를 반환한다.
const circle = new Circle(1);
console.log(circle); // {}

명시적으로 원시값 반환시 원시값 반환은 무시되고 this가 반환됨

function Circle(radius) {
  // 1. 암묵적으로 인스턴스가 생성되고 this에 바인딩된다.

  // 2. this에 바인딩되어 있는 인스턴스를 초기화한다.
  this.radius = radius;
  this.getDiameter = function () {
    return 2 * this.radius;
  };

  // 3. 암묵적으로 this를 반환한다.
  // 명시적으로 원시값을 반환하면 원시값 반환은 무시되고 암묵적으로 this가 반환된다.
  return 100;
}

// 인스턴스 생성. Circle 생성자 함수는 명시적으로 반환한 객체를 반환한다.
const circle = new Circle(1);
console.log(circle); // Circle {radius: 1, getDiameter: ƒ}

생성자 함수 내부에서 명시적으로 this가 아닌 다른 값을 반환하는것은 생성자 함수의 기본동작을 훼손하므로 생성자 함수 내부에서return문을 반드시 생략해야 함

17.2.4 내부 메서드 [[Call]]과 [[Construct]]

function foo() {}

// 일반적인 함수로서 호출: [[Call]]이 호출된다.
foo();

// 생성자 함수로서 호출: [[Construct]]가 호출된다.
new foo();

17.2.5 constructor와 non-constructor의 구분

  • constructor: 함수 선언문, 함수 표현식, 클래스
  • non-constructor: 메서드, 화살표 함수
function foo() {}

// 일반 함수로서 호출
// [[Call]]이 호출된다. 모든 함수 객체는 [[Call]]이 구현되어 있다.
foo();

// 생성자 함수로서 호출
// [[Construct]]가 호출된다. 이때 [[Construct]]를 갖지 않는다면 에러가 발생한다.
new foo();

17.2.6 new 연산자

new연산자와 함께 함수를 호출하면 해당 함수는 생성자 함수로 동작

17.2.7 new.target

  • 함수내부에서 new.target을 사용하면 new연산자와 함께 생성자 함수로서 호출되었는지 확인 가능
  • new연산자와 함께 생성자 함수로서 호출되면 함수 내부의 new.target은 함수 자신을 가르킴
    • new연산자 없이 일반 함수로서 호출된 함수 내부의 new.target은 undefined다
  • String,Number,Boolean 생성자 함수는 new연산자와 함께 호출했을 때 String, Number, Boolean객체를 생성하여 반환하지만 new연산자 없이 호출하면 문자열, 숫자, 불리언 값을 반환
const str = String(123);
console.log(str, typeof str); // 123 string

const num = Number('123');
console.log(num, typeof num); // 123 number

const bool = Boolean('true');
console.log(bool, typeof bool); // true boolean

Chapter18 함수와 일급 객체

18.1 일급 객체

함수가 일급 객체라는 것은 함수를 객체와 동일하게 사용할 수 있다는 의미

18.2 함수 객체의 프로퍼티

18.2.1 arguments 프로퍼티

  • 함수 호출시 전달된 인수들의 정보를 담고 있는 순회 가능한 유사 배열 객체이며, 함수 내부에서 지역변수처럼 사용. 함수 외부에서는 참조할 수 없다

    자바스크립트는 함수의 매개변수와 인수의 개수가 일치하는지 확인하지 않는다

  • arguments 객체는 매개변수 개수를 확정할 수 없는 가변 인자 함수를 구현할 때 유용

    • 유사 배열 객체로 동작

유사 배열 객체

length 프로퍼티를 가진 객체로 for문으로 순회할 수 있는 객체

18.2.3 length 프로퍼티

  • 함수 객체의 length프로퍼티는 함수를 정의할 때 선언한 매개변수의 개수를 가리킨다
  • arguments 객체의 length 프로퍼티는 인자의 개수를 가리키고, 함수 객체의 length 프로퍼티는 매개변수의 개수를 가리킨다

18.2.4 name 프로퍼티

함수의 이름을 나타낸다

profile
프론트엔드 개발자

0개의 댓글