221015.til

Universe·2022년 10월 15일
0

study

목록 보기
34/49

Primitive / Reference Data types

primitive data type
변수에 값이 그대로 저장되는 요소
숫자나 문자가 대표적

reference data type
변수에 reference 가 저장되는 요소
쉽게 말해 변수에 데이터를 저장하면 값이 아니라 값이 저장된 장소를가리키는 요소
array, object 가 대표적

두 데이터 타입의 차이는 복사를 해보면 가장 명확하게 알 수 있다.

var name1 = 'kim';
var name2 = name1;

name1 = 'soo';

console.log(name1);
console.log(name2);

//
soo
kim

primitive 데이터 타입은 변수에 할당된 값이 각자의 값을 가지고 있으므로
name1 변수를 변경하더라도 name2 변수에는 영향을 주지 않는다.

var name1 = { name: 'kim' };
var name2 = name1;

name1.name = 'soo';

console.log(name1)
console.log(name2)

//
{name: 'soo'}
{name: 'soo'}

reference 데이터 타입은 복사할 때 을 복사하는 것이 아닌, 값이 저장된 주소 를 복사하게 된다.
몇번을 복사하든 메모리에 저장된 똑같은 주소를 가리키게 되므로 primitive 데이터 타입처럼 복사를 하면 안된다.
전에 공부했던 깊은, 얕은 복사의 개념이다.

예제를 하나 더 보자

name1 = 'kim'
name2 = 'kim'
name3 = {name: 'kim'}
name4 = {name: 'kim'}

console.log(name1 === name2); // true
console.log(name3 === name4); // false

name1과 name2는 서로 같은 값을 가지고 있으므로 당연히 true 를 반환한다.
그러나 name3와 name4는 분명하게 서로 같은 값임에도 불구하고 false 를 반환한다.
왜 그럴까?
reference 데이터 타입은 아까 언급했다시피 변수에 주소 를 저장하게 된다.
{ } 하나에 하나의 주소를 할당하게 되므로 내부의 값이 같다고 해도 같은 주소를 가진게 아니다.
따라서 false 를 반환하게 된다.

그러면 이런 경우는 어떨까 ?

var name1 = {name: 'kim'}

function func(obj) {
	obj.name = 'soo'
}

func(name1);
console.log(name1);

//
{name: 'soo'}

오브젝트를 파라미터로 넣으면 name의 value를 ‘soo’로 변경하는 function 을 하나 만들었다.
문제가 없어 보인다.

그렇다면,

var name2 = {name: 'soo'}

function func(obj) {
	obj = {name: 'kim'}
}

func(name2);
console.log(name2);

//
{name: 'soo'}

오브젝트를 파라미터로 넣으면 해당 오브젝트에 아예 {name: ‘kim’} 이라는 오브젝트를 재할당 하는 function.
말로만 들으면 문제가 없을 것 같다.
하지만 실제로는 제대로 작동하지 않는다.
왜 그럴까 ?

함수의 파라미터는 변수의 생성과 할당을 하는 역할을 한다.
위 함수의 파라미터 obj 는 var obj = {name: ‘kim} 의 역할을 하고 있는것이다.
따라서 파라미터의 변수 obj에 새로운 할당이 되는데,
새로 할당된 obj 변수에 어떤 값을 할당한다고 해서 name2 변수에 영향을 주지는 않는다.
따라서 name2 오브젝트는 그대로 name: soo 를 출력하게 된다.

Constructor

오브젝트 생성 기계.
비슷한 오브젝트를 여러개 만들고 싶을 때 쉽게 할 수 있다.
reference 데이터 타입은 복사에 제약이 있다.
위에서 공부했던 내용처럼, 비슷한 오브젝트를 만들고 싶다고 함부로 복사할 수 없다.

그럴 때 쓸 수 있는 문법.

function Human() {
	this.name = 'kim';
	this.age = 20;
	this.job = 'soldier';
}

var man1 = new Human();
//
Human {name: 'kim', age: 20, job: 'soldier'}

관습적으로 constructor의 첫 글자의 스펠링은 대문자로 표기한다.
constructor 의 this 는 새로 생성될 오브젝트를 의미한다. instance 라고도 한다.
예를들어, this.name = ‘kim’ 을 보면
Human constructor 로 생성할 오브젝트의 name 이라는 key에 ‘kim’이라는 value 를 할당시키는 것이다.

function Human(name,age) {
	this.name = name;
	this.age = age;
	this.sayHi = function() {
		console.log(`hello! my name is ${this.name}. i'm ${this.age} year's old!`)
	}
}

var man1 = new Human('soo',19);
man1.sayHi();
//
hello! my name is soo. i'm 19year's old!

이런식으로 파라미터를 넣어서 가변적으로 할당할 수도 있고,
constructor 안에 함수를 만들어서 생성되는 오브젝트마다 함수를 사용할 수 있게 만들수도 있다.
이런 작업을 어려운말로 상속 이라고 한다고 한다.
상속의 개념은 자바스크립트에만 있다.

상속을 구현하는 또 다른 용법을 알아보자.

Prototype

var arr = [1,2,3]
console.log(arr)

//
(3) [1, 2, 3]
0: 1
1: 2
2: 3
length: 3
[[Prototype]]: Array(0)

간단하게 배열을 하나 만들었다.
그 배열을 console.log로 찍어보면 prototype 이라는 이상한 키워드가 보인다.
prototype 은 뭘까 ?

prototype 그 요소의 유전자라고 볼 수 있다.
유전자는 성격, 성질을 결정짓는 요소이다.
인간을 예로 들어보자.
환경적 요인을 배제한다면,
키가 얼마나 클 것이고 생김새가 어떨것이며 어떤 재능을 가질 수 있는지에 대한 결정요인이다.

arr 의 prototype 은 Array 라고 출력이 되는 듯 하다.
arr는 Array 라는 유전자를 가진 요소라는 뜻.
또 한가지, 인간이나 동물이 그러하듯
모든 자식들이 물려받을 속성을 의미한다.

인간의 유전자에 어떤 특정한 값을 추가한다는 개념은 잘 모르지만,
자바스크립트의 prototype 속성에 어떤 값을 추가한다면 모든 자식들이 물려받을 수 있다.

예를들어, 위의 constructor 에 prototype 을 추가한다면

function Human(name,age) {
	this.name = name;
	this.age = age;
	this.sayHi = function() {
		console.log(`hello! my name is ${this.name}. i'm ${this.age} year's old!`)
	}
}

Human.prototype.gender = 'man'

var man1 = new Human('soo',30);
console.log(man1);
console.log(man1.gender);

//
Human {name: 'soo', age: 30, sayHi: ƒ}
man

분명 constructor 에 gender 라는 key 값이 없음에도
man1.gender 는 ‘man’ 값을 출력한다.
생성한 오브젝트에 유전자로써 존재하는 것이다.
이 prototype 기능의 핵심은
부모의 유전자, 그 부모의 유전자, 그 부모의 유전자 를 거슬러 올라가 찾아내는 것에 있다.

어떤 배열을 생성할 때,

var arr = [1,2,3]

이런식으로 생성한다.
그런데 자바스크립트가 받아들이는 방식은 조금 다르다.

var arr = new Array(1,2,3)

Array 라는 constructor 에 1,2,3 을 담아서 변수 arr 에 담아주세요. 한다는 것이다.
Array, Object, Number 같은 prototype 을 자바스크립트에서 미리 내장함수로 정의해놓은 것이다.
생성된 모든 배열은 prototype: Array 라는 유전자를 가지고 태어난다.
arr 이라는 배열이 담긴 변수에
따로 sort(), forEach() 같은 함수가 담긴 key 를 따로 정의해준적이 없음에도,
Array 라는 prototype 을 가진 arr 은 해당 메소드를 상속 받아서 쓸 수 있다는 것이다.
반대로 모든 배열에 적용시킬 수 있는 함수를 prototype 을 이용해서 만들 수 있다.

Array.prototype.oddNumOnly = function() {
	for(i=0; i < this.length; i++) {
		if(this[i] % 2 === 0){
			this.splice(i,1);
		}
	}
}

let arr = [1,2,3,4,5,6,7,8,9]
arr.oddNumOnly();
console.log(arr);

잘 되는 모습.

Class

constructor 의 ES6 신 문법.

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

let man1 = new Human();

얼핏보면 다른게 없어보인다.
그런데,

class Human {
	constructor(name){
		this.name = name;
	}
	sayHi(){
		console.log(`hello! my name is ${this.name}!`)
	}
}

let man1 = new Human('soo');
man1.sayHi();

//
hello! my name is soo!

이런식으로 함수를 constructor 와 분리할 수 있다.
자식 오브젝트에 추가되지 않고 prototype 으로 추가된다.

추가로

man1.__proto__;
Object.getPrototypeOf(man1);

Human.prototype.sayName = function(){
	console.log(this.name);
}

__proto__getPrototypeOf 메소드로 부모의 prototype 을 확인해볼 수 있다.
또한 .prototype 메소드를 이용해 추가로 내장함수를 정의해줄 수도 있다.

profile
Always, we are friend 🧡

0개의 댓글