[마스터 개념] 8 | 스코프, 프로토타입

728x90

[마스터 개념] 8 | 스코프, 프로토타입

1 variable 변수

2 operator 연산자

3 function 함수

4 object 객체

5 class 클래스

7 built-in 빌트인 객체

8 array 배열

9 iterator 이터러블

10 map

11 more-operators 유용한 연산자들

12 module 모듈

13 promise 프로미스

14> scope 스코프

15> prototype 프로토타입

16 closure 클로져

17 this 

14 scope 스코프

 코드 블럭 : { }, if( ) { }, for( ) { }, function( ) { }

 

 스코프가 존재하는 이유는 이름 충돌 방지, 메모리 절약 때문이다.

 

 블럭 외부에서 블럭 내부의 변수를 참조할 수 없다. 

 

 블럭이 끝나면 자동으로 garbage collection 에 의해 소멸되는데, 글로별 변수는 종료될 때까지 계속 메모리에 유지된다.

 

 따라서 함수 내부나 블럭 안에서 필요한 경우에 필요한 곳에서 변수를 선언하고 사용해야 한다.

 

Hoisting 호이스팅

 

 코드 실행 전 변수, 함수, 클래스의 선언문을 끌어올려 선언 이전에도 호출할 수 있게 해 준다.

 

 또한 변수와 클래스는 선언만 호이스팅되며 초기화는 해당 줄에 와야 되므로, 초기화 전에 변수에 접근하면 erroro 발생한다.

 

var

 

 var 지양해야 하는 이유

 1.  키워드 없이 선언과 할당이 가능하므로 선언과 재할당의 구분이 어렵다.

 2. 중복 선언이 가능하다.

 3. 함수 레벨 스코프만 지원되고, 중요한 블록 레벨 스코프는 지원되지 않는다.

 -> 지역변수와 글로벌변수가 같아지는 상황이 초래된다.

 

Strict mode 엄격모드

 

 상단에 "use strict"; 라고 작성하면 엄격모드가 적용된다.

 

 1. delete 로 삭제 불가능

 2. let 이나 const 나 var 같은 키워드 생략 불가능

15 prototype 프로토타입

 모든 객체는 객체 간의 상속을 위하여 내부에 프로토타입이 있다. 이처럼 객체 간의 상속 고리는 프로토타입 체인으로 연결되어 있다.

 

const dog = { name: "멍멍", korean: "강아지" };

// 모든 프로퍼티에 대해 디스크립터를 다 받아옴
const descriptors = Object.getOwnPropertyDescriptors(dog);
console.log(descriptors);
// {
//    name: { value: '멍멍', writable: true, enumerable: true, configurable: true },  
//    korean: {
//      value: '강아지',
//      writable: true,
//      enumerable: true,
//      configurable: true
//   }
// }

// 하나의 키에 대한 디스크립터만 받아옴
const desc = Object.getOwnPropertyDescriptor(dog, "name");
console.log(desc);
//  { value: '멍멍', writable: true, enumerable: true, configurable: true }

 

 오브젝트의 각각의 프로퍼티는 프로퍼티 디스크립터라고 하는 객체로 저장된다.

 

const dog = { name: "멍멍", korean: "강아지" };

// 프로퍼티를 정의
Object.defineProperty(dog, "name", {
  value: "멍멍2",
  writable: false,
  enumerable: false,
  configurable: false,
});

 

 writable :  값을 변경할 수 있는지
 enumerable : 열거할 수 있는지
 configurable : 키 자체 삭제 등 수정할 수 있는지

 

Freeze, Seal, PreventExtensions

 

const mallang = { name: "mallang" };
const dog = { name: "멍멍", korean: "강아지", owner: mallang };

// freeze - 수정 X, 추가 X, 삭제 X, 프로퍼티 속성 재정의 X
Object.freeze(dog);
dog.name = "멍멍2";
console.log(dog);		// { name: '멍멍', korean: '강아지', owner: { name: 'mallang' } }
dog.age = 4;
console.log(dog);		// { name: '멍멍', korean: '강아지', owner: { name: 'mallang' } }
delete dog.name;
console.log(dog);		// { name: '멍멍', korean: '강아지', owner: { name: 'mallang' } }

mallang.name = "mallang2";
console.log(dog);		// { name: '멍멍', korean: '강아지', owner: { name: 'mallang2' } }

 

 단, 얕은 복사가 이뤄지므로 mallang 의 이름을 mallang2 로 바꿨을 때, 바꿔서 출력되는 것을 알 수 있다.

 

const mallang = { name: "mallang" };
const cat = { name: "야옹", korean: "고양이", owner: mallang };

// seal - 수정 O, 추가 X, 삭제 X, 프로퍼티 속성 재정의 X
Object.seal(cat);
cat.name = "야옹2";
console.log(cat);	// { name: '야옹2', korean: '고양이', owner: { name: 'mallang' } }
cat.age = 4;
console.log(cat);	// { name: '야옹2', korean: '고양이', owner: { name: 'mallang' } }
delete cat.korean;
console.log(cat);	// { name: '야옹2', korean: '고양이', owner: { name: 'mallang' } }

 

const mallang = { name: "mallang" };
const tiger = { name: "어흥", korean: "호랑이", owner: mallang };

// preventExtensions - 수정 O, 추가 X, 삭제 O, 프로퍼티 속성 재정의 O
Object.preventExtensions(tiger);
tiger.name = "어흥2";
console.log(tiger);	// { name: '어흥2', korean: '호랑이', owner: { name: 'mallang' } }
tiger.age = 4;
console.log(tiger);	// { name: '어흥2', korean: '호랑이', owner: { name: 'mallang' } }
delete tiger.korean;
console.log(tiger);	// { name: '어흥2', owner: { name: 'mallang' } }

 

 preventExtensions 함수를 사용하면 프로퍼티를 추가할 수 없고, 기존 프로퍼티를 유지할 때 사용할 수 있다.

 

Prototype 프로토타입

 

function Dog(name, emoji) {
  this.name = name;
  this.emoji = emoji;
  // 인스턴스 레벨의 함수
  /* this.printName = () => {
    console.log(`${this.name} ${this.korean}`);
  }; */
}

// 프로토타입 레벨의 함수
Dog.prototype.printName = function () {
  console.log(`${this.name} ${this.korean}`);
};

// 정적 레벨의 함수
Dog.hello = () => {
  console.log("Hello!");
};
Dog.hello();
Dog.MAX_AGE = 20;

 

 인스턴스 레벨의 함수 : 생성한 인스턴스마다 해당 함수를 가지고 있음

 프로토타입 레벨의 함수 : 각각의 인스턴스에서 공통적으로 가지는 프로토타입에 해당 함수를 가지고 있음

 정적 레벨의 함수 : 생성자 함수의 이름 또는 클래스 이름에서만 해당 함수를 가지고 있음

 

Prototype Inheritance 프로토타입 상속

 

function Animal(name, emoji) {
  this.name = name;
  this.korean = korean;
}

Animal.prototype.printName = function () {
  console.log(`${this.name} ${this.korean}`);
};

function Dog(name, korean, owner) {
  Animal.call(this, name, korean);
  this.owner = owner;
}

Dog.prototype = Object.create(Animal.prototype);

Dog.prototype.play = () => {
  console.log("놀자");
};

 

 call(this, name, korean) 은 super(name, korean) 과 똑같다. 

 

 create( ) 함수를 통해 

 기존 : Dog - Object, Animal - Object

  => Dog - Animal - Object

 

Mixin

 

 Object 는 단 하나의 prototype 을 가리킬 수 있는데 mixin 을 사용하면 여러 개의 함수를 상속할 수 있다.

 

const play = {
  play: function () {
    console.log(`${this.name} 놀아요`);
  },
};

const sleep = {
  sleep: function () {
    console.log(`${this.name} 자요`);
  },
};

function Dog(name) {
  this.name = name;
}

Object.assign(Dog.prototype, play, sleep);
const dog = new Dog("멍멍");
console.log(dog);
dog.play();		// 멍멍 놀아요
dog.sleep();		// 멍멍 자요

 

 assign( ) 을 통해 play 와 sleep 함수를 할당할 수 있다.

 

 

 

 

 

 

 

 

 

728x90