Javascript의 자료형과 Javascript만의 특성은 무엇일까?
1. Loosely typed, dynamic(느슨한 타입의 동적) 언어
2. JavaScript 형변환
+
연산자는 숫자보다 문자열이 우선시 되기때문에, 숫자형이 문자형을 만나면 문자형으로 변환하여 연산된다 (문자 > 숫자). 다른 연산자는 (1,*,/,%)
숫자형이 문자형보다 우선시되기 때문에 더하기와 같은 문자형으로의 변환이 일어나지 않는다. (문자 < 숫자)Object(), Number(), String(), Boolean()
와 같은 함수를 이용하는데 new 연산자가 없다면 사용한 함수는 타입을 변환하는 함수로써 사용된다.3. ==, ===(동치 비교)
2 == '2' -> true
2 === '2' -> false
4. undefined와 null의 미세한 차이들
let a;
let b = null;
console.log(a); -> undefined
console.log(b); -> null
JavaScript 객체와 불변성이란 ?
1. 기본형 데이터와 참조형 데이터
숫자, 문자열, 불리언, null, undefined, symbol
이 있습니다. 일반적으로 기본형은 할당이나 연산시 데이터가 복제
된다고 알려져있습니다. 기본형타입은 값을 복사해옵니다.객체, 배열, 함수, 정규표현식
등이 있으며 참조형 타입에는 값이 저장된 주소값을 참조해 옵니다.// 원시타입은 값이 복사되어 전달됨
let a = 1;
let b = a; //1
b = 2;
console.log(a);
console.log(b);
// 객체타입은 참조값(메모리주소, 레퍼런스)가 복사되어 전달됨
let apple = {
// 0x1234(메모리주소)
name: '사과',
};
let orange = apple; // 0x1234(메모리주소)
orange.name = '오렌지';
console.log(apple);
console.log(orange);
2. 불변 객체를 만드는 방법
3. 얕은 복사와 깊은 복사
const obj = {value: 1}
const newObj = obj
newObj.value = 2
console.log(obj.value) // 2
console.log(obj === newObj // true
obj 변수에 object를 할당하고, newObj 변수에 obj 변수의 값을 할당했습니다. 그리고 newObj 프로퍼티인 value 값을 2로 설정하고, obj.value를 콘솔에 출력하면, 2로 변경된 것을 볼 수 있습니다. 왜냐면, 얕은 복사 때문에, 사본의 데이터를 변경하더라도, 동일한 참조형 데이터 주소를 가리키고 있기에, 원본의 데이터도 변경되는 것입니다.
깊은복사 : 내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법입니다. 기본적형 타입의 데이터는 원래 깊은 복사가 진행됩니다. 객체에서 깊은 복사는 다양한 방법으로 진행됩니다. (재귀함수를 이용한 복사, JSON.stringify(), lodash 라이브러리 사용)
호이스팅과 TDZ는 무엇일까?
1. 스코프, 호이스팅, TDZ
--전역 스코프(Global Scope)는 말 그대로 전역에 선언되어있어 어느 곳에서든지 해당 변수에 접근할 수 있다는 의미이고 지역 스코프(Local Scope)는 해당 지역에서만 접근할 수 있어 지역을 벗어난 곳에선 접근할 수 없다는 의미입니다.
--자바스크립트에서 함수를 선언하면 함수를 선언할 때마다 새로운 스코프를 생성하게 됩니다. 그러므로 함수 몸체에 선언한 변수는 해당 함수 몸체 안에서만 접근할 수 있는데요. 이걸 함수 스코프(function-scoped)라고 합니다. 함수 스코프가 바로 지역 스코프의 예라고 할 수 있습니다.
-- 함수 선언문은 코드를 구현한 위치와 관계없이 자바스크립트의 특징인 호이스팅에 따라 브라우저가 자바스크립트를 해석 할 때 맨위로 끌어 올려집니다.
-- 함수 표현식은 함수 선언문과 달리 선언과 호출 순서에 따라서 정상적으로 함수가 실행되지 않을 수 있습니다. 함수 표현식에서는 선언과 할당의 분리가 생깁니다.
-- TDZ에 있는 변수에 접근하게 되면 ReferenceError: Cannot access before initialization 에러가 발생합니다.
-- TDZ는 const, let, class는 TDZ에 영향을 받습니다. 즉 const, let, class는 선언 전에 변수를 사용하는것을 허용하지 않습니다.
-- 반대로 var, function, import의 선언은 TDZ의 영향을 받지 않습니다. 특히 var 변수는 선언 전에도 사용할 수 있는 점에서 var 변수 사용을 피해 예기치 못한 오류를 방지하는 것이 좋습니다.
-- 변수가 먼저 선언이 된 경우, 초기화에 따라서 TDZ가 생깁니다. 특히 let,const와 var는 초기화 시점이 다릅니다. var는 암묵적으로 undefined로 초기화 된 상태에서 자바스크립트 코드를 읽기 때문에, TDZ에서 에러가 나지 않습니다.
2. 실행 컨텍스트와 콜 스택
-- 자바스크립트의 동적 언어로서의 성격을 가장 잘 파악할 수 있는 개념이며 모든 코드는 특정한 실행 컨텍스트 안에서 실행된다.
-- 자바스크립트는 어떤 실행컨텍스트가 활성화되는 시점에 선언된 변수들을 위로 끌어올리고 (호이스팅) 외부 환경 정보를 구성하고 this값을 설정하는 등의 동작을 수행하는데, 이로 인해 다른 언어에서는 발생할 수 없는 특이한 현상들이 발생한다.
-- 디폴트 실행 컨텍스트로ㅡ 자바스크립트 파일이 엔진에 의해 처음 로드되었을 때 실행되기 시작하는 환경이다.
-- 우리가 실행컨텍스트를 따로 구성하는 방법은 함수를 실행하는 것 뿐이다. 함수가 호출되고 실행됨에 따라서 해당 함수 안에서 생성되는 컨텍스트. 각각의 함수는 고유의 실행 컨텍스트를 가진다. 그리고 전역 실행 컨텍스트에 언제나 접근할 수 있다.
콜 스택
콜 은 호출을 뜻하고 스택은 출입구가 하나뿐인 깊은 우물 같은 데이터 구조다. 따라서 콜스택은 자바스크립트가 함수 호출을 기록하기 위해 사용하는 우물 형태의 데이터 구조이다
-- 항상 맨 위에 놓인 함수를 우선으로 실행된다. 이런 식으로 자바스크립트 엔진은 가장 위에 쌓여있는 context와 관련 있는 코드들을 실행하는 식으로 전체 코드의 환경과 순서를 보장한다.
-- 자바스크립트 엔진은 함수를 호출할 때 Execution context 를 생성하고 Call Stack에 추가합니다. 함수가 종료된 후 Creation phase, Execution phase 두 단계가 끝나면 자바스크립트 엔진이 Call Stack에서 해당 함수를 제거(pop) 하게 됩니다.
3. 스코프 체인, 변수 은닉화
-- 스코프 체인(scope chain)은 함수의 감춰진 프로퍼티인 [[Scope]]로 참조할 수 있다.
console.dir()을 사용하면, 개발자 도구로 쉽게 확인이 가능하다.
-- b() 함수에 [[Scopes]] 속성이 존재한다. 이것이 바로 스코프 체인(scope chain)이다.
자기 자신의 스코프(scope)를 제외한 자신과 가장 가까운 변수 객체의 스코프 순으로 접근하는 것을 눈으로 확인할 수 있다.
-- 정리하자면 자기 자신의 스코프(scope)를 제외한 자신과 가장 가까운 변수 객체의 모든 스코프들을 스코프 체인이라 할 수 있다.
-- 객체의 private 한 속성을 만들 수 없었던 자바스크립트에서는 몇 가지 대안을 사용해왔습니다. 다른 클래스 기반의 언어처럼 근본적으로 private 하게 만들 수 없었기 때문에 컨벤션으로 약속하거나 비은닉을 향한 자바스크립트의 여정 비슷한 효과를 주는 꼼수를 사용했었다.
-- 컨벤션을 이용한 방법으로는 관용적으로 가장 많이 사용되는 것이 _
즉 언더스코어 프리픽스를 속성 명에 사용하는 것이다.
function SomeConstructor() {
this._privateProp = 'dont touch this';
this.publicProp = 'you can touch this';
}
-- 이 방법은 private로 취급할 뿐이지 실제로는 public으로 동작하기 때문에 외부에서 얼마든지 접근할 수 있었다.
-- 근본적으로 접근이 불가능한 private 속성을 만드는 방법으로는 클로저를 이용한 방법이 있다.
function SomeConstructor() {
const privateProp = 'dont touch this';
this.publicProp = 'you can touch this';
this.doSomethingWithPrivateProp = () => { ... }
}
-- 하지만 이제는 자바스크립트에서도 진정한 의미의 private 속성을 만들 수 있게 되었다. 그 특징은 간단하게 요약하면 아래와 같다.
Stage-3 단계에 있는 스펙으로 특별한 결격 사유가 없는 한 표준 스펙이 될 것이다. 물론 변경되거나 개선될 여지는 있다.
private
과 같은 키워드를 사용하지 않는다. 대신 #
즉 샵 프리픽스를 사용한다. 키워드가 아니라 프리픽스다. 속성 명 앞에 #
이 붙으면 Private 필드로 동작한다. - Class Field Decalarations 스펙의 일부다. public과 다른 점은 클래스의 필드 선언을 통해서만 만들 수 있다. 즉 동적으로 객체에 private 필드를 추가할 수 없다.
메서드에는 제한적이다. 메서드 선언으로 사용할 수 없다. private 메서드를 만들려면 함수 표현식으로 정의해야 한다.
어디까지나 현재로서는 그렇다는 말이다. 스펙이 업데이트될 수도 있다. (Class fields and private methods: Stage 3 update)
Computed Property Name을 사용할 수 없다. #foo
자체만 식별자로 허용되고 #[fooName]
이건 문법 오류다.
모든 Private 필드는 소속된 클래스에 고유한 스코프를 갖는다. 그렇기 때문에 독특한 특징이 있다.
실습 과제
let b = 1;
function hi () {
const a = 1;
let b = 100;
b++;
console.log(a,b);
}
//console.log(a);
console.log(b);
hi();
console.log(b);
let b = 1; // 전역 스코프 👍
function hi() { // 함수 내부에서 선언된 변수들은 함수 내부에서만 유효한 지역 스코프
const a = 1;
let b = 100;
b++;
console.log(a, b);
}
// console.log(a); // a는 hi()함수 내부에서 선언된 지역 스코프이기때문에 함수 밖에서 존재하지 않음.
// 위를 동작하게 하려면 const a = 1을 함수 밖으로 꺼내야 함.
console.log(b); // 가장 첫줄의 전역스코프 b가 호출됨 👍
hi(); // 부른 함수가 실행되고 지역스코프 a = 1 과 b++로 1증가한 b = 100이 출력된다.
console.log(b); // let b = 100은 지역스코프기 때문에 여전히 전역스코프값 let b = 1을 따르는 모습 👍