let foo = 42 // foo가 number
foo = 'bar' // foo가 이제 string
foo = true // foo가 이제 boolean
함수와 연산자에 전달되는 값은 대부분 적절한 자료형(타입)으로 자동 변환되는데 이런 과정을 '형 변환(type conversion)'이라고 한다.
문자, 숫자, 논리형으로의 형 변환은 자주 일어나는 형 변환이다.
문자형으로 변환
무언가를 출력할 때 주로 일어난다.
String(value)을 사용하면 문자형으로 명시적 변환이 가능하다. 원시 자료형을 문자형으로 변환할 땐, 대부분 그 결과를 예상할 수 있을 정도로 명시적인 방식으로 일어난다.
숫자형으로 변환
수학 관련 연산시 주로 일어난다.
Number(value)로도 형 변환을 할 수 있다.
숫자형으로의 변환은 다음 규칙을 따른다.
Number(value) * 이때 변환할 수 없는 문자열 등을 넣으면 NaN이 뜸
undefined : NaN
null : 0
boolean(true/false) : 1/0
string : 처음 끝 공백 제거후, 문자열이 없으면 0, 있다면 숫자를 읽어서 변환 (실패하면 NaN)
불린(boolean)
숫자0, 빈문자열, null, undefined, NaN과 같이 직관적으로도 "비어있다고" 느껴지는 값들은 false, 그외의 값은 true
"0", " "은 비어있지 않은 문자열이므로 true
※ 동등 연산자로 좌항과 우항을 비교해서 서로 값이 같다면 'true' 다르면 'false'가 된다. '='의 개수에 따라 의미가 완전히 달라지니 주의하자.
alert (1 == 2) // false
alert (1 == 1) // true
alert (1 == '1') // true
alert ("JS" == "JAVA") // false
alert ("JS" == "JS) // true
※ 일치 연산자로 좌항과 우항이 "정확"하게 같을 때 true, 다르면 false가 된다.
alert (1 == '1') // true
alert (1 === '1') // false
alert (null == undefined) // true
alert (null === undefined) // false
alert (true == 1); // true
alert (true === 1) // false
alert (true == '1') // true
alert (true === '1') // false
alert (0 === -0) // true
alert (NaN === NaN) // false
null과 undefined는 값이 없다는 의미의 데이터 형이다. null은 값이 없음을 명시적으로 표시한 것이고, undefined는 그냥 값이 없는 상태라고 생각한다.
의도함 -> null
의도하지 않음 -> undefined
NaN(Not a Number)은 0/0과 같은 연산의 결과로 만들어지는 특수한 데이터 형인데 숫자가 아니라는 뜻이다. (또는 계산할 수 없음 이라는 뜻)
위에서 설명한 것과 같이 null과 undefined는 값이 없다는 의미의 데이터 형이다. null은 값이 없음을 명시적으로 표시한 것이고, undefined는 그냥 값이 없는 상태라고 생각한다.
alert( null === undefined ); // false
alert( null == undefined ); // true
일치 연산자 ===를 사용하여 null과 undefined를 비교하면 두 값의 자료형이 다르기 때문에 일치 비교 시 false
동등 연산자 ==는 피연산자가 undefined나 null일 때 형 변환을 하지 않는다. 즉, undefined와 null을 비교하는 경우에만 true를 반환하고, 그 이외의 경우(null이나 undefined를 다른 값과 비교할 때)는 무조건 false를 반환
string
number
boolean
undefined
null
ES6 부터 추가된 symbol
array
object
function
📌 기본형데이터는 불변성으로 한번 만든데이터는 가비지 컬렉팅을 당하지 않는 한 영원히 변하지 않는다.
참조형데이터는 객체의 내부 프로퍼티를 변경할때는 가변성으로 객체의 변수 영역이 별도로 존재한다.
1) (숫자 or 불리언).toString()
2) String(숫자 or 불리언)
3) "" + (숫자 or 불리언)
1) parseInt(정수 문자열) || parseFloat(실수 문자열)
2) Number(문자열 or 불리언)
3) + (문자열 or 불리언)
4) (문자열 or 불리언) * 1
- Boolean ( 숫자 || 문자열 || 객체 || undefined || null )
: Boolean() 생성자 함수를 new 연산자 없이 호출하여 불리언 타입으로 변환하는 방법- !! ( 숫자 || 문자열 || 객체 || undefined || null )
: 부정 논리연산자(!)를 연달아 두번 사용해서 불리언 타입으로 변환하는 방법
🔶 JavaScript Immutability[참고]
// Object freeze 객체를 불변하게 만들기
let test = {
name : 'Lee'
}
Object.freeze(test);
test.name = 'Jung';
console.log(test) // { name: 'Lee' }
🔶 얕은 복사(Shallow Copy)
🔶 깊은 복사(Deep Copy)
- 자바스크립트의 스코프는 함수 레벨 스코프를 따른다.
같은 함수 레벨에 존재하면 값을 참조할 수 있다는 건데
ES6에서 let 키워드가 도입되면서 블록 레벨 스코프를 사용할 수 있게 됐다.
🔶 전역 스코프
🔶 전역 변수
전역 스코프를 갖는 전역 변수
어디서든 참조 가능
🔶 지역 스코프
🔶 지역 변수
지역 스코프를 갖는 지역 변수
함수 내에서 선언된 변수로 해당 함수와 해당 함수의 하위 함수에서 참조 가능
🔶 암묵적 전역 변수
선언하지 않은 변수에 값을 할당하면 전역 객체의 프로퍼티가 되어 전역 변수처럼 동작한다.
하지만 변수 선언이 없었기 때문에 호이스팅은 발생하지 않는다.
(variable = 1) === (window.variable = 1)
//////////////////////////////////////
console.log('test', test);
function temp () {
test = 10;
};
temp(); // test is not defined
catName("달래");
function dogName(name) {
console.log("제 반려견의 이름은 " + name + "입니다");
}
// "제 강아지의 이름은 달래 입니다"
var : 호이스팅 시 undefined로 변수를 초기화
function : 선언된 위치와 상관없이 동일하게 호출
let, const : 호이스팅 시 변수를 초기화하지 않음. (호이스팅 대상은 맞음)
console.log(num); // 호이스팅한 var 선언으로 인해 undefined 출력
var num; // 선언
num = 6; // 초기화
console.log(num2); // ReferenceError: num2 is not defined
let num2 = 2;
//-----------------------------------------------
catName("달래"); // "제 반려견의 이름은 달래 입니다"
function catName(name) {
console.log("제 반려견의 이름은 " + name + "입니다");
}
catName("달래"); // "제 반려견의 이름은 달래 입니다"
🔶 let, const
{
// <----- TDZ가 스코프 맨 위에서부터 시작
const func = () => console.log(letVar); // OK
// TDZ 안에서 letVar에 접근하면 ReferenceError
let letVar = 3; // letVar의 TDZ 종료 ------->
func(); // TDZ 밖에서 호출함
}
: let 변수 선언 코드가 그 변수에 접근하는 함수보다 아래에 위치하지만 함수의 호출 시점이 사각지대 밖이므로정상 동작.
🔶 class
// (X)
class User extends Member {
constructor(phone) {
this.phone = phone;
super(phone);
}
}
// (O)
class User extends Member {
constructor(phone) {
super(phone);
this.phone = phone;
}
}
📌 결론
- TDZ는 선언 전에 변수를 사용하는 것을 허용하지 않는다.
- var의 사용은 의도치 않은 중복선언과 재할당으로 문제가 생길 수 있기 때문에 사용하지 않는편이 좋다.
🔶 함수 선언식 (function declartion)
function sum(a,b) {
return a + b;
}
🔶 함수 표현식 (function Expression)
const sum = function(a,b) {
return a + b;
}
📌 함수 선언식으로 작성한 함수는, 함수 전체가 호이스팅 된다고 하였는데, 전역적으로 선언하게 되면, 중복적으로 동명의 함수를 쓰게 되었을때, 원치 않는 결과를 초래할 수 있습니다. 이를 방지하려면 함수 표현식으로 작성하면 됩니다.
- var : 변수 재선언 가능
const, let : 변수 재선언 불가능- const : 변수 재할당 불가능 (상수)
let : 변수 재할당 가능- var : functional-scope 로 호이스팅됨
const, let : block-scope 로 호이스팅됨
🔶 실행 컨텍스트
Global Execution Context
Fuction Execution Context
🔶 콜 스택
🔶 스코프 체인
🔶 변수 은닉화