데이터 타입 #1
Replies: 5 comments 1 reply
-
공유하고싶은 자료 & 개인적으로 정리한 블로그 등이 있다면 여기👇👇👇에 댓글로 공유해주세요 😀 |
Beta Was this translation helpful? Give feedback.
-
JavaScript의 타입JavaScript는 느슨한 타입(loosely typed)의 동적 언어입니다. JavaScript의 변수는 어떤 특정 타입과 연결되지 않으며, 모든 타입의 값으로 할당 및 재할당이 가능합니다. let foo = 42 // foo가 숫자
foo = 'bar' // foo가 이제 문자열
foo = true // foo가 이제 불리언 원시 타입과 객체원시 타입 원시 타입의 값은 불변성(immutable)을 지닙니다. 그리고 값에 의한 전달(pass-by-value)을 합니다. 종류는 참조 타입(객체) 원시 타입을 제외한 모든 것을 객체라고 할 수 있습니다. 배열, Map, 함수 등등… 객체는 참조에 의한 전달(pass-by-reference) 방식으로 전달됩니다. 원시 타입let a = 100;
a = 50;
원시 타입은 불변성을 가지고 있기 때문에 메모리에 생성된 값이 변경되는 일은 없습니다. 식별자와 연결되어있는 메모리가 바뀌었을 뿐입니다. 원시 타입의 값 복사하기 let a = 100;
let b = a;
a = 50;
console.log(b) // 100 새로운 변수 b에 a를 할당하게 되면 변수 b의 공간에는 a가 가리키는 100의 주소값이 그대로 복사되어 변수의 메모리에 담깁니다. 그 후에 a 값이 50으로 재할당되어도 b는 영향을 받지 않습니다.
참조 타입 (객체)앞서 말한대로 원시 타입을 제외한 나머지가 참조 타입이고 배열, 객체, 함수가 대표적입니다. let a = [1, 2];
let b = a;
b.push(3);
console.log(a); // [1,2,3]
console.log(b); // [1,2,3] b에만 3을 push를 했습니다. 그러나 b에는 a의 참조값이 그래도 저장되어 있기 때문에 a에도 3이 push됩니다. (둘이 같은 참조값을 가져서 발생하는 상황)
참조 타입의 값 복사하기 참조 타입의 변수는 데이터 복사가 일어날 때 값이 담긴 주소값을 바로 복사하지 않고 참조값(값이 담긴 주소값들의 묶음의 주소값)이 복사됩니다. let obj1 = {
a: 1,
b: "bbb"
};
let obj2 = obj1;
obj2.a = 20;
console.log(obj1.a); // 20
console.log(obj2.a); // 20
console.log(obj1 == obj2, obj1 === obj2) // true, true obj2는 obj1이 가리키는 데이터 묶음의 주소를 복사합니다. 그러므로 obj2에서 프로퍼티의 값을 변경하면 값이 변경됩니다. 반면에 let obj1 = {
a: 1,
b: "bbb"
};
let obj2 = obj1;
obj2 = {
a: 20,
b: "cc"
};
obj2.a = 11
console.log(obj1.a); // 1
console.log(obj2.a); // 11
console.log(obj1 == obj2, obj1 === obj2) // false, false
일치 연산자, 동등 연산자 이용시 차이점원시 타입은 변수가 값을 가지고 있기 때문에 두 변수를 비교할 때 값을 기준으로 같은지 판단하게 됩니다. // Primitive type
let a = 3;
let b = 3;
console.log(a === b); // true
b = 5;
console.log(a === b); // false 반면 참조 타입은 변수가 참조 값을 가지고 있으므로 참조 값이 같은지를 판단합니다. 따라서 값이 같더라도 참조값이 다르다면 false를 리턴합니다. // 변수를 각각 선언하여 두 변수의 참조 값이 다른 상황.
let a = [1, 2];
let b = [1, 2];
console.log(a === b); // false
// console.log(a == b); // false
// 두 변수의 참조 값이 같은 상황.
let c = [1, 2];
let d = c;
console.log(c === d); // true
let e = [1, 2, 3];
let f = e;
f[0] = 8;
console.log(f); // [8,2,3]
console.log(e); // [8,2,3]
console.log(e === f); // 뭐가 나올까요? -> true const 사용시 차이점const 키워드는 일반적으로 변수의 초기화 이후의 값을 변경하지 못하도록 합니다. 그러나 참조 타입에서는 값이 아니라 참조 값을 변경하지 못하도록 합니다. object요소를 const로 선언했다면 내부 요소는 변경가능하지만 요소 자체를 새로 만드는 것은 참조 위치가 변경되므로 불가능합니다. // Primitive type
const a = 3;
a = 5; // TypeError: Assignment to constant variable.
// Reference type
const b = [1, 2];
b.push(3); // 가능!
console.log(b); // [1, 2, 3]
// 재정의 할 시 참조 값이 바뀌게 되므로 에러가 발생.
b = [3, 4]; // TypeError: Assignment to constant variable. 참조 타입의 값 변경도 허용하고 싶지 않다면?Object 메소드중 하나인 freeze 메소드를 사용하자 const b = [1, 2];
b.push(3);
console.log(b); // [1, 2, 3]
Object.freeze(b);
// 값을 추가할 때
b.push(4); // Cannot add property 4, object is not extensible
// 값을 제거할 때
b.splice(0, 1);
// TypeError: Cannot assign to read only property '0' of object '[object Array]' undefined vs null
undefined는 개발자가 의도적으로 할당하기 위한 값이 아니라 자바스크립트 엔진이 변수를 초기화할 때 사용하는 값입니다. 변수를 참조했는데 undefined라면 참조한 변수가 선언은 되었는데 할당이 되지 않음을 간파할 수 있습니다.
참고자료 원시타입(Primitive Type)과 참조타입(Reference Type) 원시타입과 참조 타입👀 |
Beta Was this translation helpful? Give feedback.
-
불변 객체객체의 의도치 않은 변경과 해결책객체가 의도치 않게 변경되는 원인의 대부분은 '레퍼런스를 참조한 다른 객체에서 객체를 변경' 하기 때문입니다. 자바스크립트에서 참조 타입의 데이터인 객체의 경우 메모리 힙 영역에 저장이 되어 내부 프로퍼티를 변경해도 같은 참조를 갖고 있기에 객체가 의도치 않게 변경될 수 있습니다. 이 의도치 않은 변경을 막기 위해 객체를 불변 객체화, 방어적 복사불변 객체화, 객체의 방어적 복사와 관련된 자바스크립트 메서드는 다음과 같습니다.
불변 객체화 :
|
Beta Was this translation helpful? Give feedback.
-
동적 타이핑
JS는 동적 타이핑 언어, 더 구체적으로는 동적 타이핑 종류의 하나인 덕 타이핑 기반의 언어이다. 이 덕 타이핑을 이펙티브 타입스크립트 책에서는
interface Human {
name: string;
age: number;
walk(): void;
}
function sayHello(h: Human) {
console.log(`hi, my name is ${h.name}, i'm ${h.age}`);
h.walk();
}
const chanwoo = {
name: 'chanwoo',
age: 28,
walk: () => console.log('walk... keep walk')
talk: () => console.log('shut up')
}
sayHello(chanwoo); // 정상
그렇다면 JS는 어떠한 방식으로 타입이 정의할까? 내부의 타입정의 방식을 알아보기 위해 JS의 컴파일 방식에 대해 살펴보자. JS는 JIT컴파일 방식으로 수행된다.
우리가 컴퓨터 언어를 공부할 때 컴파일의 방식에 따라 인터프리터 언어와 컴파일러 언어로 나누었다. 두 언어를 간단히 정리하면, 컴파일러 언어
인터프리터 언어
하지만 JIT 컴파일 방식은 두 방식이 아닌, 두 언어의 방식을 혼합한 방식이다. 인터프리터 언어와 동일하게 한줄씩 읽으면서 기계어로 변경하여 실행하는 방식이지만 여기에 컴파일의 과정 뿐 만 아니라 최적화하는 과정까지 포함된다. 크롬의 JS 엔진인 V8엔진의 컴파일 방식을 그림으로 살펴보자.
기본적으로
크롬의 엔진인 V8엔진은 재사용의 잠재적인 가능성이 있는 함수나 객체를 기계어로 캐싱해둔다고 한다.(초록색 선) 하지만 우리가 주목할 것은 worst case인 빨간색 선이다. 이는 기존의 캐싱된 기계어 코드를 재사용하지 않고 다시 컴파일 후 실행하는 과정으로 성능 저하가 발생한다. 갑자기 타입 얘기하다말고 V8 엔진의 동작을 이렇게까지 깊게 본 이유가 뭐냐? 기존의 캐싱된 데이터를 사용하지 못하는 이유가 바로 오늘 학습하고 있는 동적 타이핑에 있기 때문이다. 동일한 함수이더라도 함수가 참조하고 있는 객체의 변화가 실행시점에 발생할 수 있는데, 이렇게 객체 타입의 변화가 발생하면 캐싱된 데이터를 재사용하지 못한다. (그렇다고 실제로 실행이 안되는 것은 아니다. 그저 캐싱된 기계어를 사용하지 못한다는 것일 뿐) 타입의 정의가 실행하는 관점에서 보면 위에서 보았던 function func(obj) {
return obj.x;
} 아주 단순한 함수가 있는데, 컴파일러가 해당 함수를 캐싱하는 과정에서 아래의 질문을 고려한다.
분명하게도 함수의 동일성을 판단하는 데에 더 많은 조건들이 필요하겠지만 참고한 영상에서는 위의 질문에 대해서만 설명하고 있다. 즉, 타입의 동일성을 판단할 때 객체 내부 속성의 구조(속성과 메서드의 종류와 갯수)의 일치를 확인한다는 것을 알 수 있다. 실제 함수 수행의 내부 동작은 이러하다.
sayHello({name: 'chanwoo', age: 28, walk: () => console.log('walk... keep walk')})
sayHello({name: 'iu', age: 24, walk: () => console.log('run')}) // 캐싱 사용 가능
sayHello({name: 'joy', age: 24, walk: () => console.log('run'), job: 'singer'}) // 재컴파일 JS 상에서 위의 코드는 전혀 문제가 발생하지 않는다. 실행 시점에 객체의 타입을 확인해보았을 때, 함수가 요구하는 속성과 메서드를 모두 가지고 있기 때문에 세번의 호출 모두 성공적으로 가능하다. (덕타이핑) 하지만 최적화 관점에서는 객체의 타입과 그 실행 과정이 다르다. 두번째 호출에서는 함수의 전달되는 객체에 대한 캐싱이 이루어져서 즉각적인 실행이 이루어진다. 하지만 세번째 호출에서는 인자의 객체가 새로운 속성값을 가지게 되고 기존의 결론적으로, JS가 보장하는 타입의 확장성을 통해 충분히 실행 가능한 코드이더라도 확장된 타입을 사용하면 재컴파일이 발생하기 때문에 성능저하가 발생할 수 있다. 이러한 성능 저하를 피하기 위해서는 동일한 함수에는 동일한 타입, TS에서 말하는 타입보다 엄격한 형태로 재호출하는 것이 좋다. 결론
1. JS는 동적 타이핑의 종류 중 하나인 덕타이핑 기반이다.2. JS 엔진 내부적으로 타입을 정의할 때에는 속성과 메서드의 종류와 갯수의 일치를 확인한다. 이는 캐싱된 기계어 코드를 사용하기 위함이다.3. 그렇다고 JS가 수행이 되지 않는 것은 아니다. 하지만 성능 저하를 피하기 위해서는 동일한 함수에는 동일한 타입, TS에서 말하는 타입보다 엄격한 형태로 재호출하는 것이 좋다.참조 |
Beta Was this translation helpful? Give feedback.
-
데이터 타입Javascript의 데이터 타입은
Chromium에서 Javascript 데이터 타입은 ECMAScript 사양에 따라 구현된다.
자바스크립트에서 원시타입은 어떻게 구현되었을까? 식별자와 연결되어있는 메모리가 바뀌었을 뿐은 어떤 의미일까? ecma262 사양ECMAScript 2023 기준
4.4.23 Number valueprimitive value corresponding to a double-precision 64-bit binary format IEEE 754-2019 value
4.4.24 Number typeset of all possible Number values including the special “Not-a-Number” (NaN) value, positive infinity, and negative infinity 4.4.25 Number objectmember of the Object type that is an instance of the standard built-in Number constructor
Chromium 구현/**
* A JavaScript number value (ECMA-262, 4.3.20)
*/
class V8_EXPORT Number : public Primitive {
public:
double Value() const;
static Local<Number> New(Isolate* isolate, double value);
V8_INLINE static Number* Cast(v8::Data* data) {
#ifdef V8_ENABLE_CHECKS
CheckCast(data);
#endif
return static_cast<Number*>(data);
}
private:
Number();
static void CheckCast(v8::Data* that);
}; c++의 class로 정의된 /**
* A Number object (ECMA-262, 4.3.21).
*/
class V8_EXPORT NumberObject : public Object {
public:
static Local<Value> New(Isolate* isolate, double value);
double ValueOf() const;
V8_INLINE static NumberObject* Cast(Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
#endif
return static_cast<NumberObject*>(value);
}
private:
static void CheckCast(Value* obj);
}; Number의 New와 Number object의 New는 어떤 차이가 있을까? 우선 첫번째 인수인 Isolate에 대해 알아보자. IsolateV8 엔진에서 Isolate는 V8 엔진의 독립 실행형 인스턴스에 대한 컨테이너이다. 동일한 프로세스에서 실행될 수 있는 엔진의 다른 인스턴스들 간에 엔진의 전역상태 및 리소스(메모리 및 CPU 시간등)를 격리하는데 사용된다. 각 Isolate에는 고유한 Heap 및 가비지 컬렉터와 Number, String, Object 같은 고유한 빌트인 객체 집합이 있다. 이러한 리소스와 상태 분리를 통해 V8 엔진의 여러 인스턴스가 서로 간섭하지 않고 동시에 실행될 수 있다. V8 Number 클래스에서 isolate 매개변수는 새 Number 객체가 연결되어야 하는 Isolate를 지정하는 데 사용된다. Number Class는 V8 API의 일부이고, isolate를 사용하는 이유는 Chromium 같은 클라이언트와 V8이 상호작용하는데 필요하다. Isolate 매개변수를 사용해서 API가 올바른 V8 엔진 인스턴스로 요청을 보낼 수 있게 도와준다. 우리는 이제 아래 식을 이해할 수 있게 되었다.
isolate 는 V8 엔진의 인스턴스 생성용이고, 3.14는 우리가 할당할 값이다. 이상한 점이 있다. Number class의 New 메서드인데 왜 원시타입이 아닌
|
Beta Was this translation helpful? Give feedback.
-
주제 키워드는
✨데이터 타입✨
입니다.
☘️ 하위 주제 키워드
⏳스레드에 소요시간도 적어주면 좋습니다! (ex) 호찬 90분 소요
참고링크
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures
https://developer.mozilla.org/en-US/docs/Glossary/Immutable
Beta Was this translation helpful? Give feedback.
All reactions