항해 99 2주차 - JS 문제

·2022년 9월 23일
0

항해99

목록 보기
2/2

어제 3일을 거의 밤새다시피 했던 과제를 4일차에 힘들게 서버까지 합쳐서 과제를 제출했다!
이제 금요일이 되자마자 받은 또 다른 과제!

쉽지 않겠지만 이번주도 화이팅해야겠다.

아래 문제들을 읽고 설명해서 포스팅 하는게 이번 2주차 첫번째 과제다.

🤞1번

자바스크립트는 느슨한 타입(loosely typed)의 동적(dynamic)언어라고 한다.

let foo = 42 // foo 는 int
foo = 'bar' // foo 는 string
foo = true // foo 는 boolean

이처럼 모든 타입의 값으로 재할당이 된다.
좋은점도 있지만 실행 도중 변수에 예상 못한 타입때문에 에러가 발생할 수 있습니다. 런타임시 확인이 안되기에 보완을 위해 아직은 JS가 아닌 TypeScript를 쓰는 방법으로 보완이 가능하다.

JS 동적이라 형변환이 유연하게 되는데 엔진의 필요에 따라 [암시적변환] 또는 [명시적변환]이 된다.

암시적변환

지맘대로 변환이 되는건데

산술 연산자

더하기(+) 연산자는 숫자보다 문자열이 우선시 되기때문에, 숫자형이 문자형을 만나면 문자형으로 변환하여 연산된다. (문자 > 숫자)

// 더하기(+)
number + number // number
number + string // string
string + string // string
string + boolean // string
number + boolean // number
50 + 50; //100
100 + “점”; //”100점”
“100” + “점”; //”100점”
“10” + false; //”100"
99 + true; //100

다른 연산자(-,*,/,%)는 숫자형이 문자형보다 우선시되기 때문에 더하기와 같은 문자형으로의 변환이 일어나지 않는다. (문자 < 숫자)

//다른 연산자(-,*,/,%)
string * number // number
string * string // number
number * number // number
string * boolean //number
number * boolean //number
“2” * false; //0
2 * true; //2

명시적변환

개발자가 의도를 가지고 데이터타입을 변환시키는 것을 말한다.

타입을 변경하는 기본적인 방법은 Object(), Number(), String(), Boolean() 와 같은 함수를 이용하는데 new 연산자가 없다면 사용한 함수는 타입을 변환하는 함수로써 사용된다.

var trans = 100; //Number
Object(trans); //100
console.log(typeof trans); //Number
String(trans); //”100"
console.log(typeof trans); //String
Boolean(trans); //true
console.log(typeof trans); //Bolean

다른 자료형을 숫자타입으로 변형하는 방법

Number()는 정수형과 실수형의 숫자로 변환

Number(“12345”); //12345
Number(“2”*2); //4

parseInt()는 정수형의 숫자로 변환

문자열이 숫자 0 으로 시작하면 8진수로 인식하고(구형브라우저 O, 신형브라우저X), 0x, 0X 로 시작한다면 해당 문자열을 16진수 숫자로 인식한다. 또한 앞부분 빈 공백을 두고 나오는 문자는 모두 무시되어 NaN을 반환한다.

parseInt(“27”) //27
parseInt(0033); //27
parseInt(0x1b); //27
parseInt(“ 2”); //2
parseInt(“ 2ㅎ”); //2
parseInt(“ ㅎ2”); //NaN

parseFloat() 는 부동 소수점의 숫자로 변환한다.

parseInt()와는 달리 parseFloat()는 항상 10진수를 사용하며 parseFloat() 또한 앞부분 빈 공백을 두고 나오는 문자는 모두 무시되어 NaN을 반환한다.

parseFloat(“!123”); //NaN
parseFloat(“123.123456”); //123.123456
parseInt(“123.123456”); //123
parseFloat(“ 123.123456”); //123.123456
parseFloat(“ a123.123456”); //NaN

다른 자료형을 문자타입으로 변형하는 방법

String()

String(123); //”123"
String(123.456); //”123.456"

toString()는 인자로 기수를 선택할 수 있다. 인자를 전달하지 않으면 10진수로 변환한다.

var trans = 100;
trans.toString(); //”100"
trans.toString(2); //”1100100"
trans.toString(8); //”144"
var boolT = true;
var boolF = false;
boolT.toString(); //”true”
boolF.toString(); //”false”

toFixed()의 인자를 넣으면 인자값만큼 반올림하여 소수점을 표현하며 소수점을 넘치는 값이 인자로 들어오면 0으로 길이를 맞춘 문자열을 반환한다.

var trans = 123.456789;
var roundOff = 99.987654;
trans.toFixed(); //”123"
trans.toFixed(0); //”123"
trans.toFixed(2); //”123.46"
trans.toFixed(8); //”123.45678900"
roundOff.toFixed(2); //”99.99"
roundOff.toFixed(0); //”100"

참조: [https://medium.com/gdana/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%ED%98%95%EB%B3%80%ED%99%98%EC%9D%80-%EB%91%90%EA%B0%80%EC%A7%80%EB%8B%A4-b46875be4a88]

undefined와 null의 차이

둘다 원시 자료중 하나이지만 undefined는 값이 할당되지 않은 변수는 기본적으로 undefined 값을 가지고
[null]은 어떤 값이 비어있음을 의도적으로 표현할 때 사용된다.

🤞2번

JavaScript 객체와 불변성이란 ?

JavaScript의 데이터타입 중 원시 타입은 값이 변하지 않는 불변 값이고,
객체는 값이 바뀔 수 있는 변경 가능한 값이다.

원시 타입 이외의 모든 값은 객체(Object) 타입이며 객체 타입은 변경 가능한 값(mutable value)이다.

원시타입은
Boolean, null,undefined,Number,String,Symbol
이렇게 6가지가 존재한다.

불변 객체를 만드는법

불변 객체를 만들기 위해서는 2가지가 있는데 const와 Object.freeze()을 사용하는것이다.

const 키워드는 변수를 상수로 선언할 수 있다, 일반적으로 상수로 선언된 변수는 값을 바꾸지 못한다.

객체 재할당은 불가능하지만 객체의 속성은 변경 가능하다.
재할당이 불가능 한 이유는 변수와 값(객체) 사이의 바인딩 자체가 변경이 되기 때문에 상수인 test변수는 재할당이 불가능한 것이다.

객체의 속성이 변경가능 한 이유는 실제 객체가 변경은 되지만 객체와 변수사이의 바인딩은 변경이 되지 않기 때문에 객체의 속성은 변경가능한 것이다.

때문에 비록 재할당은 불가능하지만 객체의 속성을 변경함으로 인해 변수에 바인딩된 객체의 내용까지 변경이 되기 때문에 불변객체라고 하기는 힘들다.

Object.freeze()
"객체를 동결하기 위한 메소드" 이다.

Object.freeze()는 동결된 객체를 반환하지만 객체의 재할당은 가능하다.

위와 같이 객체의 재할당은 가능하다. 때문에 Object.freeze()도 불변 객체라고 할 수는 없을 것 같다.

그럼 결국 불변 객체는 어떻게 만들 수 있냐면..

const와 Object.freeze()를 조합하여 만들 수 있다. (const의 재할당불가 + Object.freeze()의 객체속성 변경불가)

const키워드로 바인딩 된 변수를 상수화 시킨 다음, Object.freeze()로 해당 변수를 동결 객체를 만들면 객체의 재할당과 객체의 속성 둘 다 변경불가능한 불변 객체가 된다.

🤞3번

호이스팅(hoisting)

인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미한다. var로 선언한 변수의 경우 호이스팅 시 undefined로 변수를 초기하는 반면 let과 const로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않는다.
(이래서 사람들이 요즘 var을 쓰지 말라고 했던건가?)

호이스팅을 설명할 땐 주로 "변수의 선언과 초기화를 분리한 후, 선언만 코드의 최상단으로 옮기는" 것으로 말하곤 한다. 따라서 변수를 정의하는 코드보다 사용하는 코드가 앞서 등장할 수 있다고 한다. 다만 선언과 초기화를 함께 수행하는 경우, 선언 코드까지 실행해야 변수가 초기화된 상태가 되는것을 주의해야한다.

다음 예제를 보면 더 이해가 잘 되는데,

function catName(name) {
  console.log("제 고양이의 이름은 " + name + "입니다");
}

catName("호랑이");

/*
결과: "제 고양이의 이름은 호랑이입니다"
*/

이건 당연히 우리가 흔히 생각하는 결과고

catName("클로이");

function catName(name) {
  console.log("제 고양이의 이름은 " + name + "입니다");
}

/*
결과: "제 고양이의 이름은 클로이입니다"
*/

이렇게 함수를 선언하기 전에 먼저 호출했을 때에도 정상적으로 작동한다.

더 다양한 예제를 보자면

// 예제 1
// y만 호이스팅 대상

x = 1; // x 초기화. x를 선언하지 않은 경우 선언. 그러나 명령문에 var가 없으므로 호이스팅이 발생하지 않음
console.log(x + " " + y); // '1 undefined'
// JavaScript는 선언만 호이스팅하므로, 윗줄의 y는 undefined
var y = 2; // y를 선언하고 초기화

// 예제 2
// 호이스팅은 없지만, 변수 초기화는 (아직 하지 않은 경우) 변수 선언까지 병행하므로 변수를 사용할 수 있음

a = '크랜'; // a 초기화
b = '베리'; // b 초기화

console.log(a + "" + b); // '크랜베리'

이렇게 볼 수 있다.

(좀 신기하긴 하다. 아무런 생각없이 사용하고 있었다리.)

Temporal Dead Zone (TDZ)에 대해서

TDZ는 컴퓨터가 값을 사용하여 변수를 완전히 초기화하는 순간까지 변수에 액세스할 수 없는 블록의 영역입니다. 변수 초기화가 완료되기 전에 변수에 액세스하려고 한다고 가정할때 JavaScript는 ReferenceError를 발생시킵니다. 따라서 JavaScript가 이러한 오류를 발생시키지 않도록 하려면 TDZ 외에서 변수에 액세스해야 합니다.

그럼 스코프는 뭐고 TDZ는 뭔가?

블록의 TDZ는 블록의 로컬 범위 시작 부분에서 시작합니다. 컴퓨터가 값을 사용하여 변수를 완전히 초기화할 때 끝납니다.
다음 예시를 보자

{
  // bestFood’s TDZ starts here (at the beginning of this block’s local scope)
  // bestFood’s TDZ continues here
  // bestFood’s TDZ continues here
  // bestFood’s TDZ continues here
  console.log(bestFood); // returns ReferenceError because bestFood’s TDZ continues here
  // bestFood’s TDZ continues here
  // bestFood’s TDZ continues here
  let bestFood = "Vegetable Fried Rice"; // bestFood’s TDZ ends here
  // bestFood’s TDZ does not exist here
  // bestFood’s TDZ does not exist here
  // bestFood’s TDZ does not exist here
}

위의코드에서 블록의 TDZ는 여는 중괄호({)에서 시작하여 컴퓨터가 문자열 값이 "Vegetable Fried Rice"인 bestFood를 초기화하면 끝납니다.
이 코드를 실행시키면 ReferenceError가 뜰텐데 이런 이유는 우리는
console.log()를 이니셜라이제이션이 끝나기전에 bestFood에 접근하려고 했기 때문이다. 말하자면 우리는 TDZ에 bestfood를 호출한거다.

그러니 bestfood에 접근하기 위해서 아래의 코드처럼 하면된다.

{
  // TDZ starts here (at the beginning of this block’s local scope)
  // bestFood’s TDZ continues here
  // bestFood’s TDZ continues here
  // bestFood’s TDZ continues here
  // bestFood’s TDZ continues here
  // bestFood’s TDZ continues here
  // bestFood’s TDZ continues here
  let bestFood = "Vegetable Fried Rice"; // bestFood’s TDZ ends here
  console.log(bestFood); // returns "Vegetable Fried Rice" because bestFood’s TDZ does not exist here
  // bestFood’s TDZ does not exist here
  // bestFood’s TDZ does not exist here
}

다음 예시도 보자

{
  // TDZ starts here (at the beginning of this block’s local scope)
  // bestFood’s TDZ continues here
  // bestFood’s TDZ continues here
  // bestFood’s TDZ continues here
  // bestFood’s TDZ continues here
  // bestFood’s TDZ continues here
  // bestFood’s TDZ continues here
  let bestFood; // bestFood’s TDZ ends here
  console.log(bestFood); // returns undefined because bestFood’s TDZ does not exist here
  bestFood = "Vegetable Fried Rice"; // bestFood’s TDZ does not exist here
  console.log(bestFood); // returns "Vegetable Fried Rice" because bestFood’s TDZ does not exist here
}

위의 예시에도 undefined로 제일처음 출력된것을 볼 수 있는데 우리가 bestFood를 호출하기도 전에 사용하려 했기 때문이다.

그래서 const혹 let변수를 사용하고 싶다면 특정 value를 정해주는게 중요하다.

하!지!만

var는 다르게 작동한다.

다음 코드를 보자

{
  // bestFood’s TDZ starts and ends here
  console.log(bestFood); // returns undefined because bestFood’s TDZ does not exist here
  var bestFood = "Vegetable Fried Rice"; // bestFood’s TDZ does not exist here
  console.log(bestFood); // returns "Vegetable Fried Rice" because bestFood’s TDZ does not exist here
  // bestFood’s TDZ does not exist here
  // bestFood’s TDZ does not exist here
}

다음을 실행하면 undefined가 뜨는것을 볼 수 있는데. 그이유는 JavaScript가 자동으로 정의되지 않은 변수를 호이스트된 var 변수에 할당했기 때문이다. 말하자면 컴퓨터가 var변수를 호이스트 할때 값이 정의되지 않은 상태에서 변수를 자동으로 초기화 하기 때문이다.

반대로 let과 const는 그렇지 않다.

https://www.freecodecamp.org/news/javascript-temporal-dead-zone-and-hoisting-explained/

🤞실습과제 1번

이대로 출력은 하면

console.log(b); // 1

hi(); // 1, 101

console.log(b);//1

이렇게 출력이 된다. 첫번째 1은 전역변수로 선언된 let b = 1;가 그대로 출력된 값
2번째 hi( )는 함수 hi의 값이 출력 된것인데, a의 값 1과 b의 원래값 100에 ++로 1이 추가되어 나온값 101이 출력 된다.
3번째 1 역시 첫번째와 똑같은 이유로 1이 출력 되었다.

주석 처리 되어있는 console.log(a); 가 있는데 주석을 해제하면 오류가 난다.
왜냐면 a의 값이 없기 때문이다.

코드상에는 a가 보이지만 그 a는 hi()라는 함수안에 지역변수이지 전역변수가 아니기에 출력이 되지 않았다. a의 값을 출력하고 싶다면 const a =1 을 hi()함수 밖으로 빼주면 hi()안에 값에도 주석을 해제했던 console.log(a);에도 1이 출력된다.

🤞실습과제 2번

자바스크립트에서 따옴표 안에 들어가있는건 숫자도 "문자"로 인식한다.
1 == "1"; //true
1 === "1"; // false
로 출력이 되는데 ==은 자동형변환 기능으로 첫번째 숫자 1을 문자로 형변환이 되는거다.

하지만 밑에 === 은 정확히 일치해야지 true로 표시되는 문법이여서 false로 출력이 된다.

profile

0개의 댓글