[JavaScript] 객체

soyeon·2022년 7월 5일
0

JavaScript -> 객체 지향 언어, 객체 기반 언어
javascript를 구성하는 대부분은 객체이다.
mutable한 특징을 가진다.

객체?

: 0개 이상의 property의 집합이다. property는 key와 value의 쌍으로 이루어진다. property는 property attribute를 가진다.

  • 객체 예시
var person = {
	name : '홍길동',  // 이 하나를 property라고 부른다. (key:value)
    age : 20
}

Json
: JavaScript 객체 형태인 데이터를 전달하기 위한 표현법
JavaScript 객체와는 다르다.

객체 생성하는 방법

: 만드는 방식에 따라 객체 구조가 달라진다.

객체 literal

: 가장 간단한 방법이지만 똑같은 형태의 객체를 여러개 만들 때 비효율적이다.
key를 쓸 때 Namig Rule에 부합하면 따옴표 생략 가능하다.

var obj = {
    name: '홍길동',
    printName: function myPrint() {
        console.log(`내 이름은 ${this.name}`);
    },
    "!myPhone": "010-1234-5678",
    10: 300
};
  • 간단한 객체 literal
var age = 20;

var obj = {
	userName: '홍길동',
    getName: function() {  // property인데 통상적으로 method라고 부른다.
      console.log(this.userName);
    },
  	setName() {  // 얘가 JavaScript(ES6)에서 말하는 method이다.
      ...  
    },
    age  // age: age를 축약한 표현이다.
}

ES6에서 추가된 객체 literal 확장

  • 확장 표현 방식
    : 변수의 이름을 key로 쓰고 변수의 값을 value로 사용한다.
let x = 1;
let y = 2;

const obj = {x, y}  // 확장 표현 방식

console.log(obj);

실행 결과 : { x: 1, y: 2 }
  • 메소드 축약
    : JavaScript에서 말하는 명시적 메소드이다.
let myObj = {
    name: '홍길동',
    printName() {
        console.log(this.name);
    }
}

myObj.printName()

실행 결과 : 홍길동

Object 생성자 함수

: "new" keyword를 이용해서 생성자 함수를 호출한다.
-> 그 결과 instance가 생성된다.

const person1 = {};
// 객체 literal을 이용한 객체 생성
// -> instance라고 부르지 않는다.

const person2 = new Object();
// 생성자 함수를 이용한 객체 생성
// -> instance라고 부른다.

일반적으로 첫 글자를 대문자로 쓰면 생성자 함수이고, 아니면 일반 함수로 쓰인다.

JavaScript의 대표적인 built-in 생성자 함수
: JavaScript engine이 기동하면 생성된다. 전역 객체(window)에 property로 등록된다.

  • Object()
  • Array()
  • String()
  • Number()
  • Boolean()
  • Function()
  • Math
  • Json

-> 여기에서 Math와 Json은 생성자 함수가 아니다. 이 둘을 가지고는 객체를 만들지 못한다. 나름대로의 정적 메소드를 사용하여 만든다.

var str = new String('홍길동');

built-in_Object

생성자 함수(User defined)

: 생성자 함수를 "new" keyword로 호출한다. 그러면 instance가 만들어지고, 일반 객체와는 다르다. 생성자 함수의 이름 식별자는 PascalCase를 사용한다.
return을 쓰지 않는다. 묵시적으로 생성된 instance reference인 this가 return 된다. primitive value를 리턴하면 무시한다.

function Person() {

}

const person1 = Person();
console.log(person1);

const person2 = new Person();
console.log(person2);

var person3 = {};
console.log(person3);

실행 결과 : undefined
		   Person {}
		   {}

일반적인 생성자 함수 코드

function Person(name) {
    this.name = name;
    this.getName = function() {
        return `내 이름은 ${this.name}`;
    }
}

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

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

실행 결과 : 내 이름은 아이유
		   내 이름은 김연아
// 함수 선언문
function add(x,y) {
    return x + y;
}

var inst = new add();
console.log(inst);  // add {}

function createUser(name, role) {
    return {name, role};
}

inst = new createUser();
console.log(inst);  // { name: undefined, role: undefined }

this

: this 키워드는 일반 함수인 경우에도 있고, 생성자 함수인 경우에도 존재한다.

일반 함수에서의 this : window
생성자 함수에서의 this : 앞으로 만들 instance를 가리키는 reference
메소드에서의 this : 현재 사용하는 객체

<참고>
JavaScript engine이 코드를 실행하기 위해 기동한 이후 일어나는 일
1. buit-in 객체(생성자 함수 포함) 생성한다.
2. 실행 환경에 맞는 global 객체를 생성한다.
- browser 환경 -> window
- Node.js 환경 -> global

// 생성자 함수
function Circle(radius) {
    this.radius = radius;
    this.getDiameter = function() {
        return 2 * this.radius;
    }
}

const circle = Circle(5);  // 일반함수로 사용된 것이다.
console.log(radius);  // 5  
// 일반함수이니까 window가 global 객체이고, window의 property로 radius가 생성된 것이다.

일반 객체 : 호출(call, invoke) 불가능
함수 객체 : 호출 가능
이 기능을 위해 함수 객체는 내부 slot과 내부 method를 가지고 있다.
1. [[Call]] : 함수를 외부에서 호출하면 JavaScript engine에 의해 실제적으로 호출된다. 이 내부 메소드를 가지고 있는 객체를 Callable 객체라고 한다.
2. [[Constructor]] : 객체가 생성이 될 때 이 내부 메소드를 이용한다.

함수 객체를 생성하기 위해 new가 붙으면 constructor를 호출하고, new가 붙지 않으면 call을 호출하게 되는 것이다.

함수 생성

  • constructor
    : 함수선언문, 함수표현식, class -> [[Constructor]] 존재
    이 3개로만 instance를 만들 수 있다. 모든 함수가 생성자인 것은 아니다.
  • non-constructor
    : arrow function, ES6 함수 축약형(method) -> [[Constructor]] 존재 X
// 함수 선언문
function foo() {}

// 함수 표현식
var bar = function() {}

// 객체의 property로 함수가 할당
const barx = {
    x: function() {}
}

new foo();  // foo 함수 객체가 내부 메소드 [[Constructor]] 가지고 있다.
new bar();  // 내부 메소드 [[Constructor]] 가지고 있다.
new barx.x();  // 내부 메소드 [[Constructor]] 가지고 있다.

const arrow = () => {}

new arrow();  // arrow is not a constructor

const obj = {
    x() {}
}

new obj.x();  // TypeError: obj.x is not a constructor

Object.create() method

: 객체를 생성할 때 객체의 상위 prototype 객체를 직접 지정할 수 있다.

const obj = Object.create(null);  // 상위 prototype 객체가 없다. -> obj.__proto__ 을 사용할 수 없다.

console.log(obj.__proto__);

// 이런 경우 해결 방법
// Object가 가지고 있는 method를 이용한다.

// 객체의 상위 prototype 객체를 들고 온다.
console.log(Object.getPrototypeOf(obj));

실행 결과 : undefined
		   null

ES6 -> class

class Person {
    constructor(name) {
        this.name = name;
    }
}

const me = new Person('홍길동');

객체 사용하는 방법

property의 동적인 추가와 삭제

추가

  • dot notation( . )
  • bracket notation( [ ] )
    : 항상 문자열 형태로 넣어주어야 한다.
var obj = {
    myName: '홍길동'
}

obj.myAge = 20;
obj.!myPhone = "010-1234-5678";  // 식별자 Naming Rule에 맞지 않아 쓸 수 없다.
obj['!myPhone'] = "010-1234-5678"; // 브라켓에는 항상 문자열 형태로 써야 한다.

console.log(obj);

실행 결과 : { myName: '홍길동', myAge: 20, '!myPhone': '010-1234-5678' }
var obj = {
    10: 100,
    let: '권장X',  // 키워드는 사용할 수는 있지만 권장되지는 않는다.
    myName: '홍길동',
    '!myName': '김길동',
    myName: '김연아'  // key 값을 중복해서 사용해도 된다. 덮어쓴다.
};

console.log(obj);

실행 결과 : { '10': 100, let: '권장X', myName: '김연아', '!myName': '김길동' }

삭제

  • delete keyword
delete obj.myAge;

객체 수정 제어

: JavaScript 객체는 자유롭게 property의 추가, 삭제, 값의 read, 값의 write가 가능하다.

  1. 확장 금지(Object.preventExtensions()) -> property 추가가 안된다.
  2. 밀봉금지(Object.seal()) -> property의 추가와 삭제가 안된다.
  3. 동결(Object.freeze()) -> property의 추가, 삭제, property 값의 변경이 안된다.
'use strict';  // 이 코드를 추가하면 person.adreess = '서울'; 과 같은 코드에서 에러가 발생한다.

const person = {
    name: 'Lee',
};

// 객체가 확장이 가능한지
console.log(Object.isExtensible(person));  // true
person.age = 20;
console.log(person);  // { name: 'Lee', age: 20 }

Object.preventExtensions(person);

person.address = '서울';
console.log(person);  // { name: 'Lee', age: 20 }

Primitive value(원시값) VS 객체

: immutable vs mutable

  • 객체 선언시 메모리 구조
var obj = { name: '홍길동' }

메모리 구조

  1. obj라는 식별자가 특정 메모리를 가리키고 있다. 이 메모리에는 객체 데이터가 저장되어 있는 주소가 저장되어 있다.
  2. 값을 읽으려면 obj 식별자가 가르키고 있는 곳에 저장되어 있는 주소를 따라가면 된다.

Primitive value는 식별자가 데이터가 저장된 곳을 가리키고 있다.

  • Array-like Object (유사 배열 객체)
let myStr = '홍길동';

// primitive type을 마치 객체(배열)처럼 사용
console.log(myStr[0]);  // 홍
console.log(myStr.length);  // 3

메모리구조

원래는 primitive value였는데, myStr[0]을 실행하는 순간 객체가 만들어지고, 내부 슬롯에 값이 복사된다. 그리고 식별자가 해당 객체를 가르킨다. 객체가 되었기 때문에 나름대로의 property를 붙인다. ex) length, 0: 'H', 1: 'e', 2: 'l' ...
객체 사용이 끝나면 내부슬롯으로 가지고 있던 값을 다시 primitive value로 보내준다.

let myStr = 'Hello';

myStr[0] = 'h';  // 원래 값은 바뀌지 않는다.

console.log(myStr);

실행 결과 : Hello

객체의 property가 바뀌게 되는 것이다. 실제 값은 바뀌지 않는다.

  • 객체 복사
let person = { name: 'Lee' }
let copy = person;

레퍼런스(식별자가 가르키고 있는 데이터가 있는 주소)가 복사되기 때문에 같은 객체를 가리키게 된다.

전역 객체

: 개발자가 의도적으로 생성할 수 없다. JavaScript engine에 의해서 생성된다.
사용하는 platform에 따라 다르다. window와 global을 합쳐서 globalThis(ES11)라고 한다.

  • 브라우저 환경에서는 window 하단에 붙는다.
    • DOM(Document Object Model)
    • BOM(Browser Object Model)
    • XMLHttpRequest
    • var로 선언된 전역변수 (let/const 전역변수는 붙지 않는다.)
    • 묵시적 전역
    • NaN -> NaN
    • undefined -> undefined

platform
: 무언가를 실행시켜 줄 수 있는 환경
ex) os, window, 브라우저, ...

Implicit global(묵시적 전역)

: 이런 현상은 좋지 않다. 코드의 신뢰도를 떨어뜨린다.
언어적인 차원에서 사용하지 못하게끔 처리할 수 있다. -> Strict mode

function foo() {
    x = 10;  // 전역변수화(window 객체의 property로 붙는다.)
}

foo();

console.log(x);

실행 결과 : 10

Strict Mode

: 'use strict';
1. 일반적으로 전역에 잡지 않는다. 다른 일반 library들이 동작을 안 할 수 있다.
2. 일반적으로 즉시 실행 함수(IIFE)를 만들어서 사용하는게 일반적이다.

(function() {
    // non-strict mode
    var let = 10;
    // inner function, nested function
    function foo() {
        'use strict';
       
        let = 20;
    }
}());

실행 결과 : SyntaxError: Unexpected strict mode reserved word 오류 발생

strict mode 사용시 주의점

  • implicit global(묵지석 전역)을 사용할 수 없다.
  • 변수, 함수, 매개변수가 delete로 삭제가 안된다.
'use strict';

var obj = {}

delete obj;

실행 결과 : SyntaxError: Delete of an unqualified identifier in strict mode. 오류 발생
  • this의 의미가 달라진다.
    : 일반 함수에서 this -> window 객체 (strict mode 사용시 undefined)

0개의 댓글