[JavaScript] 4. Property & Prototype

Nam_JU·2022년 7월 9일
0

KaKao Cloud School

목록 보기
4/19



1. Property Attribute

내부 슬롯과 내부 메소드

내부 슬롯과 내부 메소드는 JS엔진의 구현 알고리즘을 설명하기 위해 ECMAScript 사양에서 사용하는 의사 프로퍼티와 의사 메소드 이다.

모든 객체는 [[Prototype]]이라는 내부 슬롯을 갖는다.
원칙적으로 직접 접근할 수 없지만 [[Prototpe]]내부 슬롯의 경우,
_ proto __ 을 통해 간접적으로 접근 할 수 있다

  • 객체는 property의 집합이다 (ket, value로 이루어짐)

  • property는 property attribute를 가진다

  • javascript 객체는 내부 slot과 내부 method가 들어 있다

  • 내부 slot → [ [ … ] ]
  • 내부 method → [ [ … ] ] - 개발자가 직접적으로 사용할 수 없다 (js Engine에 의해 사용)

property attribute ⇒ properrty를 생성할때 해당 ploperty의 상세를 나타내는 격식



Property Attribute

JS엔진은 프로퍼티를 생성할 때 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의 한다. 프로퍼티는 데이터 프로퍼티와 접근자 프로퍼티로 구분 할 수 있다.

  • 데이터 프로퍼티 Data Property : 키와 값으로 구성된 일반적인 프로퍼티.
  • 접근자 프로퍼티 Accessor Property : 자체적으로는 값을 갖지않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 호출되는 접근자 함수로 구성된 프로퍼티


데이터 프로퍼티 Data Property

  1. property의 값 [ [ value ] ]
  2. property값은 수정할 수 있는지 여부[ [ writable] ]
  3. 해당 property가 열거될 수 있는지 여부 (반복할 수 있는지) [ [ enumerable ] ]
  4. property attribute를 재정의(재할당) 할수 있는지 [ [ configurable ] ]
//property attribute를 확인해보아요
const person = {
    name: 'lee',
    age: 20
}

// person이라는 객체에 name이라는 attribute를 가져와라 
console.log(Object.getOwnPropertyDescriptor(person, 'name'));
// log : { value: 'lee', writable: true, enumerable: true, configurable: true }

프로퍼티 정의 Property Define

객체를 만들면 객체의 특정 property를 고정하고 싶을때 Property define

Object.defineProperty() 를 사용해서 만들어낼 수 있다

for in : 열거

const person = {
    age: 20
};

// person.name = '홍길동';
//defineProperty 하나의 프로퍼티만 설정 
Object.defineProperty(person, 'name', {
    value: '홍길동',
    writable: false,
    enumerable: false, //열거
    configurable: true //재할당
});

console.log(person);
console.log(Object.getOwnPropertyDescriptor(person, 'name'));

person.name = '아이유';
console.log(person);
console.log( Object.keys(person));

for(let idx in person){
    console.log(idx); //property key
}

for(let value of person){
    console.log(value); //property value
}


JS 객체보호 (객체 변경 방지)

  1. 확장 금지 (Object.preventExtensions() )

    객체에 새로운 property 추가할 수 없다

  2. 밀봉 ( Object.seal() )

    property의 추가와 삭제가 안된다

  3. 동결 ( Object.freeze() )

    property의 추가 삭제. 값 property 값의 변경이 안된다

  • 코드
'user strict';
 
const person = {
    name: 'lee'
};

// 객체가 확장이 가능한지 - property 추가가 가능한지
console.log(Object.isExtensible(person)); //true

person.age = 20;
console.log(person); //{ name: 'lee', age: 20 }

// 확장을 금지시켜보기
Object.preventExtensions(person);
person.addres = '서울';
console.log(perosn);

Object.seal(person);
delete person.name;
console.log(person);

Object.freeze(person);
person.name = '아이유'
console.log(person);


2. 생성자 함수에 의한 객체 생성

대표적인 생성자 함수 (built-in)

  • Array()
  • Object()
  • String()
  • Number()
  • Boolean()
  • Fucntion()

2-1. Object 생성자 함수를 이용한 객체 생성

new keyword를 사용해서 생성자 함수 호출이 가능하다 ( 인스턴스라고함)

 //객체 리터럴을 이용한 객체 생성
 //instance라고 할 수 없다
 const person1 = {};
 console.dir(person1);
 
 //생성자 함수를 이용한 객체 생성
 // => instance : 생성자함수를 기반으로 나온것은 인스턴스
 const person2 = new Object();
 console.dir(person2);

2-2. (UserDefine 사용자 정의) 생성자 함수

클래스의 역할을 생성자함수가 한다
생성자 함수를 new 키워드로 호출하면 인스턴스가 만들어지고 일반 객체와 다르다

//함수 선언문으로 사용자 함수 만들기
//이름 식별자는 pascalCase - 대문자{관용적으로 생성자 함수는 대문자를 사용한다}
function Person(){

    //함수에서 return문을 적지 않으면 undefined로 리턴된다 
}

//리터럴로 만든 객체
const person1 = Person();
console.log(person1); //undefined

//생성자로 만든 객체 (인스턴스)
const person2 = new Person();
console.log(person2); //Person{}

//객체 리터럴
var person3 = {} 
console.log(person3); // {}
  • 생성자 함수는 reutrn을 쓰지 않는다
    - 묵시적으로 생성된 instance reference인 this가 리턴된다

  • this는 언제 쓸까
    1. 일반 함수 → window
    2. 생성자함수 → 생성된 instance
    3. 메소드에서 사용 → 현재 사용되는 객체
//생성자 함수에서 return 구문이 있을때
// primitive value를 리턴하면 안에서 만든 this.암묵적으로 리턴된다
function Person(name){
    this.name = name;
    this.getName = function(){
        return `내 이름은 ${this.name}`;
    }
    //생성자 함수를 할때는 return구문이 없는게 맞다
    return 100;
}

const person1 = new Person('아이유');
const person2 = new Person('김연아');

console.log(person1.getName());
console.log(person2.getName());


내부 메소드 [[Call]]과 [[Construct]]

함수 선언문 또는 함수 표현식으로 정의한 함수는 일반적인 함수로서 호출 할 수 있는 것은 물론 생성자 함수로서 호출 할 수 있다.
생성자 함수 = new 연산자와 함께 호출하여 객체를 생성하는 것을 의미한다


함수는 객체임으로 일반 객체와 동일하게 동작할 수 있다.
함수 객체는 일반객체가 가지고 있는 내부 슬롯과 내부 메서드를 모두 가지고 있기 때문이다

JS 엔진이 코드를 실행하기 위해 기동하면

  1. built -in 객체 (생성자 함수를 포함) 생성
  2. 실행 환경에 맞는 global 객체를 생성한다
    • browser 환경 ⇒ window
    • Node.js 환경 ⇒ global

일반 객체는 호출(call, invoke)을 할 수 없다

함수 객체는 호출을 할 수 있다

  • 이 기능을 위해 함수객체는 내부 slot , 내부 method를 가지고 있다
  • 객체는 [ [call ]], [[constructor]] 을 갖고 있는 놈만 호출이 가능하다
  • 그런데 함수는 [[call]], [[ constructor]] 모두 갖고 있다. 그래서 호출 가능
  • 이 내부 메소드를 가지고 있는 객체를 Callable 객체라고 한다
  • 모든 함수 객체는 Callable 객체이다
  • 객체가 생성이 될때 내부 method를 이용

function foo(){}

//함수에 property를 붙임 - primitive value
foo.myName = '홍길동';
// 함수도 넣기 
foo.getName = function(){
            //this foo 객체
    console.log(this);
}

foo(); //함수 호출
new foo(); //생성자 함수 호출

foo.getName(); //메서드 호출

모든 함수가 생성자 함수가 아니다

  • [[ Constructor]]가 있다 constructor
    • 함수 선언문
    • 함수 표현식
    • 클래스 Class
  • [[ Constructor ]]가 없다 non-constructor
    • 화살표 함수
    • ES6 함수 축약법

함수 객체의 Property

  • 일반 객체에 비해 더 가지고 있는 Property
    1. arguments property는 arguments 유사배열 객체를 property의 value로 가진다
    2. caller property: 비표준이다 : 모두 자신을 호출한다
    3. legth propety : parameter의 갯수
    4. name property : 함수의 이름
    5. prototype property: 해당 함수(생성자 함수)가 생성하는 인스턴스가 내부슬롯 [ [Prototype ]] 로 참조하는 객체를 가리킨다
      • constructor만 가지고 있다


3. 프로토타입 Prototype

자바스크립트는 객체 기반의 프로그래밍 언어이며 자바스크립트를 이루고 있는
거의 모든것이 객체
다. 원시타입 Primitive type의 값을 제외한 나머지 값들은 모두 객체다.

객체지향 프로그래밍

객체 지향 프로그래밍은 절차지향적 관점에서 벗어나 여러개의 독립적 단위, 객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임을 말한다.

실존의 문제를 프로그래밍에 접목식키기 위해 문제의 성질이나 특징을 나타내는 속성으로 나눴다. 여기서 필요한 속성만 간추린것이 추상화이다.

이처럼 객체지향 프로그래밍은 객체의 상태를 나타내는 데이터 상태, 데이터를 조작할수 있는 동작을 하나의 논리적 단위로 묶어서 생각한다. 이것을 프로퍼티 Property와 메소드 Method라 부른다.


상속과 프로토타입

상속 Inheritance는 객체지향 프로그래밍의 핵심으로 객체의 프로퍼티 또는 메소드를 다른 객체가 상속받아 그대로 사용할 수 있는 것을 말한다. JS는 프로토타입을 기반으로 상속을 구현하여 불필요한 중복을 제거한다.

자바스크립트는 Prototype 프로토타입을 기반으로 상속을 구현한다


프로토타입 객체

프로토타입 객체란 객체지향 프로그래밍의 근간을 이루는 객체간 상속을 구현하기 위해 사용된다. 프로토타입은 어떤 객체의 상위(부모)객체의 역할을 하는 객체로서 다른 객체에 공유 프로퍼티를 제공한다. 프로토타입을 상속받은 하위(자식)객체는 상위 객체의 프로퍼티를 자신의 프로퍼티처럼 자유롭게 사용할 수 있다.

모든 객체는 [[Prototype]]라는 내부 슬롯을 가지며, 이 내부 슬롯의 값은 프로토타입의 참조다. [[Prototype]]에 저장되는 프로토타입은 객체의 생성방식에 의해 결정된다.
즉, 객체가 생성될때 객체 생성 방식에 따라 프로토타입이 결정되고 [[prototype]] 에 저장된다.

  • constructor property : 생성자 함수 객체를 가르킨다


모든 객체는 하나의 프로토타입을 갖는다.
모든 프로토타입은 생성자 함수와 연결되어있다.

  • 자바스크립트 엔진이 시작 { 코드 실행 전}
    1. built-in 객체 생성 (Object, STring)
    2. 전역 객체를 만든다 (자바스크립트가 어느곳에서 실행하냐에 따라 전역객체 이름이 다르다. 브라우저에서하면 window라는 이름의 객체가 생성됨)
    3. creation phase : window 객체(property로 이루어짐 - key, value)가 자지고 있는
      전체 객체 window에 프로퍼티가 생성된다 (Person)
      윈도우 객체에 프로퍼티로 붙는것은 var 만 해당 (let, const는 안됨)
    4. execation phase
  • 모든 객체는 [ [ Prototype ] ] 내부 슬롯을 포함하고 있다

var tmp = 100; //window property로 붙인다 

// 생성자 함수로 사용할 목적으로 만들었다 
// 함수 선언문
function Person(name){
    
    //property를 재정의
    //생성자 함수로 만들어질 instance가 가지는
    //property를 설정한다
    this.name = name;
    //생성자의 this는 앞으로 내가 만들 객체를 가르킴

}

const person = new Person('홍길동');
person.name;


_ _proto__ 접근자 프로퍼티

  • 모든 객체는 _ _proto__ 접근자 프로퍼티를 통해 자신의 프로토타입, [[Prototype]] 내부 슬롯에 간접적으로 접근 할 수 있다.
  • _ _proto__ 접근자 프로퍼티는 객체가 직접 소유하는 프로퍼티가 아니다. Object.prototype의 프로퍼티다.
  • 모든 객체는 상속을 통해 Object.prototype._ _proto__접근자 프로퍼티를 사용할 수 있다.

_ _proto__ 접근자 프로퍼티를 코드내에서 직접 사용하는 것은 권장하지 않는다.
프로토타입의 참조를 취득하고 싶은 경우에는 Object.setPrototypeOf 메서드를 사용하도록 하자

  • scopechain ⇒ 식별자를 찾음
  • propertychain ⇒ 객체의 프로퍼티를 찾으려는 매커니즘
    언어마다 객체지향과 상속을 풀어가는게 다 다르다
    자바스크립트는 프로토타입 기반의 객체로 상속을 한다
//생성자함수
function Circle(radius){
    this.radius = radius;

    //공통적인 동작
    this.getDiameter = function(){
        return 2 * this.radius;
    }
}

const circle1 = new Circle(5); // new 함수가 여러개 만들어진다 
const circle2 = new Circle(10);

            //같은 값 인지 확인 , 메모리 주소 값이 같은지 확인 
console.log(circle1.getDiameter === circle2.getDiameter); //false - 인스턴스가 생성될때마다 함수도 따로 생성됨
                                              //함수하나가 만들어지면 그와 관련된 값들도 추가생성됨 -> 메모리 낭비
//생성자함수
function Circle(radius){
    this.radius = radius;

    Circle.prototype.getDiameter = function(){
        return 2 * this.radius;
    }

}
const circle1 = new Circle(5); // new 함수가 여러개 만들어진다 
const circle2 = new Circle(10);

            //같은 값 인지 확인 , 메모리 주소 값이 같은지 확인 
console.log(circle1.getDiameter === circle2.getDiameter); //true



왜 이런 구조를 가지게 되었을까

상속을 구현하기 위해서 Inheritance

  • 코드의 재활용을 높이기 위해

JS 모든 객체는 [ [ Prototype] ] 이라는 내부 슬롯을 가진다

자신의 상위 프로토타입 객체를 가진다 → 객체 생성 방법에 따라 종류가 달라진다

알아 둬야 하는 Propety가 더있다.

  • Prototype
  • constructor
  • _post _

Rest Parameter (ES6)

  • arguments 무사배열 객체 대신 사용 → 가변 인자 함수를 만들 때 사용
  • Rest parameter는 Array로 사용 → 가변 인자 함수를 만들 때 사용
    • ‘ …’ 점 3개로 표현
    • Parameter의 제일 마지막에 위치
    • Rest parameter는 2개 이상 나올 수 없다
function foo(param1, ...args)
{
    console.log(arguments);
    // [Arguments] { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }
    console.log(args);
}   //[ 1, 2, 3, 4, 5 ]

foo(1,2,3,4,5);

arguments, Rest parameter → 둘다 이용할 수 있다

단, arrow function에서는 arguments를 못쓴다

Rest parameter만 이용이 가능하다

profile
개발기록

0개의 댓글