JavaScript

자바스크립트 개발자가 알아야 할 33가지 개념 #2 원시 타입(Primitive Type)

Ghost. 2022. 10. 12. 23:28

원시값과 참조값

Primitive Value - 단일데이터 - Copy by Value

  • Strings, Numbers, Booleans, null, undefinded ,Symbol (ES6에 새롭게 추가됨)
  • 원시 타입은 변하지 않는 (immutable) 속성을 갖는다.
  • ? 원시 타입은 자신을 변경할 수 있는 메소드를 갖지 않기 때문이다.
  • 작은 메모리가 사용되고 일반적으로 스택 메모리에 저장된다.
  • 저장된 값을 이용하여 복사본을 만든다.
  • ? 변수에 새로운 값을 할당하면 변수가 참조하는 메모리공간의 주소가 바뀐다.

Object- 복합데이터 - Copy by Reference

  • All other object
  • 더 많은 메모리를 차지하고 보통 힙으로 저장된다.
  • 저장된 메모리 공간을 복제한다.
    • 변수가 가지고 있는 메모리주소를 이용해서 변수의 값에 접근한다.
    let dog = {
    	name: "코코",
    };
    let cat = dog
    cat.name = "밍";
    console.log(dog.name) // 밍
    console.log(cat.name) // 밍
    
  • Primitive Type이 아닌것은 object이다. object라는 개념은 함수들과 배열들도 포함된다.</aside>
    "dog" === "dog"; // true
    14 === 14; // true
    
    {} === {}; // false
    [] === []; // false
    (function () {}) === (function () {}); // false
    

<aside> ⚠️ 모든 함수들도 Object이다.</aside>

// Primitive Types
true instanceof Object; // false -> boolean
null instanceof Object; // false -> null
undefined instanceof Object; // false -> undefined
0 instanceof Object; // false -> number
'bar' instanceof Object // false -> string

// Non-primitive types
const foo = function () {}
foo instanceof Object; // true -> function;

함수는 1급 객체이다.

함수는 특별한 프로퍼티들을 가진 새로운 형태의 객체이다.

const dog = function (coco) {};
dog.name; // "dog"
dog.length; // 1
dog.age = 3 
dog.age // 3
  • 다른 함수의 인자값으로 넘겨질 수 있다.
  • 변수나 데이터에 할당 가능하다.
  • 객체의 리턴 값으로 리턴 가능하다.

<aside> ⚠️ 이러한 특성은 자바스크립트의 객체들이 갖는 특성과 같다.</aside>

METHODS(행동양식)

  • 모든 메서드는 함수이지만 모든함수가 메서드인것은 아니다.
  • METHODS는 객체 속성으로 추가된 함수
const myMath = {
	PI: 3.14159,
	square(num) {
		return num * num;
	},
	cube(num) {
		return num ** 3;
	}
}

생성자 함수

  • 생성자 함수란 리턴 값으로 생성하는 함수를 객체 그 자체로서 반환하는 함수이다.
  • 생성자 함수와 일반 함수에 문법적인 차이는 없지만 두가지의 규칙이 존재한다.
  1. 반드시 ‘new’연산자를 붙여 실행한다.
  2. 객체 자체를 리턴한다.
function User(name,age) {
		this.name = name;
		this.age = age;
}
const user = new User("CoinKing",27);
user
//User {name: 'Coinking",age: 27}

<aside> ⚠️ 어떤 함수든 생성자 함수가 될 수 있습니다.</aside>

const Foo = function () {};
const bar = new Foo();
bar; // {}
bar instanceof Foo; // true
bar instanceof Object; // true
  • 생성자 함수는 object를 리턴한다.
  • object에 새로운 프로퍼티들을 할당하기 위해 this를 함수의 몸통 안에서 사용한다.

<aside> ⚠️ 새로운 오브젝트를 만들기 위해서 생성자 함수를 사용할수 있다.</aside>

  • 우리가 “baz” 값으로 초기화된 bar라는 프로퍼티를 가진 object를 많이 만들고 싶다면 그로직을 캡슐화하는 생성자 함수를 만들수있다.
const Foo = function () {
	this.bar = "baz";
};
const qux = new Foo();
qux; // { bar: "baz" }
qux instanceof Foo; // true
qux instanceof Object; // true
  • new키워드 없이 단순히 Foo()를 실행한다면 Foo는 일반적인 함수처럼 동작할것이다.
  • Foo()라는 함수를 전역 컨텍스트에서 실행시키게 되면, 전역 컨텍스트 시점의 this 인 window 객체에 bar라는 프로퍼티가 추가된다.
Foo(); // undefined
window.bar; // "baz"
  • 일반 함수를 생성자 함수로 실행한다면 함수의 역할을 한다기보다 그저 새로운 함수 오브젝트를 반환할 뿐이다.
const pet = new String('dog');
// pet은 원시 타입의 "dog" 값을 갖는 것이 아니라 생성자 함수로 생성된 String 객체를 갖게 된다.

래퍼 오브젝트 (Wrapper Object, 포장 오브젝트)

  • String, Number, Boolean와 같은 원시타입을 new 키워드로 생성하면 원시타입에 대한 래퍼 오브젝트(Wrapper Object) 가 생성된다.
  • String은 문자열이 인자로 들어왔을 때, 원시 문자열(Primitive String)을 생성하는 전역 함수이다.
    • String = 인자로 들어온 값을 문자열로 바꾼다.
String(1337); // "1337"
String(true); // "true"
String(null); // "null"
String(undefined); // "undefined"
String(); // ""
String("dog") === "dog"; // "true"
typeof String("dog"); // "string"

하지만 new 키워드를 붙인다면 String은 여전히 생성자 함수로 쓰일수 있다.

const pet = new String("dog");
typeof pet; // "object"
pet === "dog"; // false

그리고 위의 생성자는 래퍼 오브젝트(Wrapper Object)라고 불리는 새로운 Object를 만들것이다.

위의 코드에서 새로운 Object는 ‘dog’라는 문자열을 다음과 같은 프로퍼티로 나타낸다.

{
	0: "d",
    1: "o",
    2: "g",
    length: 3
}

<aside> ⚠️ 래퍼 오브젝트(Wrapper Objects)는 오브젝트 래퍼(Object Wrappers)라는 이름으로도 자주 불립니다.

</aside>

오토박싱(Auto-Boxing)

흥미로운 것은 원시 타입 문자열 생성자와 일반 오브젝트 생성자 둘다 String 함수를

이용한다는 것이다. 더욱 흥미로운 것은 원시 문자열 타입에서 .constructor를 이용하여

생성자 프로퍼티를 확인할 수 있다는 것이다. 우리는 원시 타입은 메소드를 가질수 없다고 배웠는데……

const pet = new String("dog");
pet.constructor === String; // true
String("dog").constructor === String; // true

위의 예에서, length 라는 프로퍼티에 접근하기 위해 자바스크립트는 foo를 오토박싱하고 이것을 래퍼 오브젝트에 넣는다. 그리고 래퍼 오브젝트의 length 프로퍼티에 접근하고 값을 이용한 뒤에는 지워버린다. 이 모든 과정은 foo라는 원시타입 변수에 전혀 영향을 미치지 않는다. foo는 여전히 그저 원시 타입 문자열일 뿐…..

이러한 일련의 과정은 우리가 원시 타입에 프로퍼티를 할당하려고 할 때 자바스크립트가 왜 아무런 경고나 에러메시지를 출력하지 않는지를 알려준다,. 원시 타입은 프로퍼티를 가질 수 없는데도 말이죠. 왜냐하면 프로퍼티를 할당할 때 잠시 원시 타입을 이용한 Wrapper Object(래퍼 오브젝트)를 만들고 거기에 할당하기 때문이다.

const foo = 42;
foo.bar = "baz"; // Assignment done on temporary wrapper object
foo.bar; // undefined

만일 undefined나 null과 같이 래퍼 오브젝트가 없는 원시 타입에 대해서 프로퍼티를 할당하려고 하면 자바스크립트는 에러메시지를 나타낼 것입니다.

const foo = null;
foo.bar = "baz"; // Uncaught TypeError: Cannot set property 'bar' of null
Reference