2.값_2

악음·2021년 7월 12일
1

i will know javascript

목록 보기
5/12
post-thumbnail

2.2 문자열

흔히 문자열은 단지 문자의 배열이라고 생각한다. 엔진이 내부적으로 배열을 쓰도록 구현되었는지는 모르곘지만 자바스크립트 문자열은 실제로 생김새만 비슷할 뿐 배열과 같지 않다는 사실을 알아야한다.
이또한 유사배열....

다음 두값을 보면

let a ="foo"
let b=["f","o","o"]

문자열은 배열과 같은 모습이다 그리고 둘다 length, indexOf(), concat()같은 값을 가진다.
때문에 다음과같이 쓸수 있다.

a.length // 3
b.length //3

a.indexOf('o') //1
b.indexOf('o') //1

그렇다면 배열에 문자가 들어가있다고해서 똑같은 "문자배열"이라고 할수있을까? 그렇지 않다

a[1]="0"
b[1]="0"
a // "foo"
b // ["f","0","o"]

위 코드를 보면 알수있듯이 둘의 차이점은 문자열은 불변값(Immutable) 배열은 가변값(Mutabel)이라는점이다 그렇게 때문에

  • 문자열 매서드는 그 내용자채를 변경하는 것이 아는 새로운 문자열을 생성한 뒤 반환한다.(원본은 바뀌지 않는다 이러한안 계념은 react.js의 state와도 관련이 있다.)
  • 반면 대부분의 배열 메서드는 그자리에서 곧바로 원소를 수정한다.(불변한 매서드들은 filter, map, join, concat)
// 문자열 매서드
let c =a.toUpperCase()
a===c //false
a // "foo"
c // "FOO"

//배열 매서드
b.push("i")
b // ["f","0","o","i"]

여기서 문자열을 다룰 떄 유용한 대부분의 배열 매서드는 사실상 문자열에 쓸수 없다.
하지만 문제열에 대해 순수 배열의 불변 매서드를 빌려 쓸수는 있다.

var c =Array.prototype.join.call(a,"-")
var d =Array.prototype.map.call(a,(v)=>{
	return v.toUpperCaer()+"."
})
c // "f-o-o"
d // "F.O.O"

다음은 문자열 순서를 거꾸로 뒤집는 코드이다(면접시 자주 출제된다)
배열에는 가변 매서드 reverse()가 존재하지면 문자열에는 존재하지 않는다. 가변 매소드는 빌려쓰는 것 조차 안되니 다음과같은 방법(hack)이 있다

var c =a.split("")  // 배열 변환
        .reverse()  // 배열 뒤집기
        .join("")	// 다시 합치기

책에선 복잡한 문자가 섞여있는 경우 이방법은 통하지 않는다고한다. 때문에 정교한 라이브러리가 필요한다 마티아스 바이넨의 "에스레베르(리버스를 거꾸로)"를 참고하자

여기서 배열과 문자열을 자유롭게 오갈수 있도록

split() 
join()

적절히 사용하도록하자.

2.3 자바스크립트의 숫자

자바스크립트의 숫자 타입은 number 가 유일하며 정수(Integer), 부동 소숫점 숫자(Fractional Decimal Number)을 모두 아우른다.
자바스크립트에선 진정한 정수가 없다는 이유로 오랫동안 욕을 먹었다고한다.
현재 자바스크립트에서 정수는 부동 소수점 값이 없는 상태이다(예:42.0은 곧 정수 42와 같다)
또한 모든 스크립트 언어를 통틀어 대부분의 현대 프로그래밍 언어는 IEEE 754표준(부동 소수점 표준)을 따르고 있다.
자바스크립트도 이와 같으며 정확히는 "배 정도(Double Precision)표준 포맷(64비트 바이너리)"를 사용한다.

궁금하신분들은 따로 검색해보시길

2.3.1 숫자구문

자바스크립트 숫자 리터럴은 10진수이다

let a =42
let b =42.3

소수점 앞 정수가 0이면 생략가능

let a =0.42// .42

소수점 이하가 0일 때도 생략 가능하다

let a =42.0 // 42

또한 소수점 이하 0은 뗀다

let a = 42.3000 //42.3
let b = 42.0 //42

아주 큰값이나 아주 작은 숫자는 지수형으로 표시하며 .toExponential() 메서드의 결과값과 같다

let a =5E10 // 50000000000
a.toExponenetial() //"5e+10"

let b =a*a //2.5e+21

let c =1/a
c // 2e-11

숫자 값은 Number 객체 래퍼(Wrapper)로 박실 할 수 있기 때문에 Number.protoType메서드로 접근할 수도 있다 예를 들면 toFixed()메서드는 지정한소수점 이하 자리수까지 숫자를 나타낸다.(문자열로 반환)

let a =42.59

a.toFixed(0) // "43"
a.toFixed(1) // "42.6"
a.toFixed(2) // "42.59"
a.toFixed(3) // "42.590"

추가로 toPrecision()으로는 소수점 뿐만아니라 정수까지도 유효 숫자를 지정할 수 있다.
(결국 반올림을 할 자리수를 지정해주면된다)

let a=42.59
// 반올림 몇번쨰 자리까지 올리는지 지정해준다.
a.toPrecision(1) // "4e+1" "40"
a.toPrecision(2) // "43"
a.toPrecision(3) // "42.6"
	

여기서

  • Number.prototype.toPrecision.call()
  • Number.prototype.toFixed.call()
    을 사용할땐
    1번째 인자로 변환할 숫자를 2번째 인자로 자릿수를 넘기면 된다.

두 메서드는 숫자 리터럴에서 바로 접근 할 수 있으므로 굳이 변수를 사용하지 않아도 되지만 소수점이 있을경우 프로퍼티 접근자(accessor, .)가 아닌 숫자 리터럴의 일부로 해석되므로 .연산자를 사용할땐 조심하자.

// 잘못된 구분
42.toFixed(3) //SyntaxError

//이유는 42. 까지 숫자로 인식 엑세서로 접근 하지 않은 체로
//toFixed를 호출했기 때문이다. 따라서 다음과같이 사용야한다

(42).toFixed(3) // "42.000"
0.42.toFixed(3) // "0.420"
42..toFixed(3) // "42.000"
42 .toFixed(3) // "42.000"

2.3.2 작은 소수 값

다음은 널리 알려진 이진 부동 소수점 숫자의 부작용 문제이다
(이는 IEE 754 표준을 따르는 모든 언어에서 공통적인 문제이다)

0.1+0.2===0.3 //false 정확히는 0.3000000000000000004 정도에 가깝다 (같은건 아님)

실제로 테스트해보면 0.1+0.2=하면 정확한 0.3이 나온다

일단 이부분은 정리하지 않고 넘어가도록 한다.

2.3.3 안전한 정수 범위

정수는 Number.MAX_VALUE (1.7976931348623157e+308)보다 훨씬 작은 수준에서 안전한 범위가 정해져 있다.
안전하게 표현할수있다는 의미는 표현한 값과 실제 값이 정확하기 일치한다고 장담할 수있을 정도를 의미한다.

정수의 안전한 정수 범위는 (Number.MAX_SAFE_INTEGER~Number.MIN_SAFE_INTEGER)
9,007,199,254,740,991~-9,007,199,254,740,991이다

사실 프로그래밍을 하다보면 이렇게 큰수를 맞닥뜨리는 경우는 데이터베이스에서 64비트 ID를 처리할 때가 대부분이라고한다 64비트 숫자는 숫자타입으로 정확하게 표시할 수없으므로 string타입으로 지정한다.

이러한경우가 아니더라도 어쩔수없이 큰수를 다뤄야한다면 BigNumber 유틸리티 사용을 권장한다(라이브러리)

2.3.4 정수인지 확인

ES6 부터는 Number.isInteger()으로 어떤 값의 정수 여부를 확인한다.

	Number.isInteger(42) //true
	Number.isInteger(42.0000) //true
	Number.isInteger(42.3) //false

안전한 정수 여부는 Number.isSafeInteger()으로 체크한다.

	Number.isSafeInteger(10002022002020200202020200202) //false
	Number.isSafeInteger(Number.MAX_SAFE_INTEGER) //true

2.3.5 비트 정수 (부호 있는)

정수의 안전범위가 대락 9천조이지만 32비트 숫자에만 가능한 연산이 있으므로 실제범위는 훨씬 줄어든다.
실질적은 안전범위는 Math.pow(-2,31)~Math.pow(2,31)까지 이다(2147483648 ~ -2147483648)

2.4 특수값

타입별로 자바스크립트 개발자들이 조심해서 사용해야할 특수한 값들이 있다.

2.4.1 값 아님을 표현하는 값

undefined 타입의 값은 undefined밖에 없고 null 타입도 값은 null뿐이다. 그래서 이 둘은 타입과 같이 항상 같다

undefined와 null에 각각 의미를 부여해서 사용할 수도 있다.

  • null은 빈 값이다.
  • undefined는 실종된(missing) 값이다

혹은

  • null은 예전에 값이 있었지만 현제는 없는 상태
  • undefined는 아직 값을 가지지 않는 것이다 (이게 더 이치에 맞다 리터럴이 없은 변수는 undefined이기 때문)

위와 같이 개인의 스타일에 따라 혹은 팀의 컨벤션에 따라 어떤식으로 의미를 '정의'하던지 유용하게 쓰면된다

null은 식별자가 아닌 특별한 키워드이므로 null이라는 변수에 뭔가 할당할 수는 없다(이런짓을 시도하는 사람이 있긴있을까?)
그런데 undefined는 식별자로 쓸 수 있다(?) - 느슨한 모드 한정으로

2.4.2 Undefined

느슨한 모드에서는 전역 스코프에서 undefined란 식별자에 값을 할당할 수 있다(하지말자 이런짓은..)
현재 undefined에 값을 할당하더라도 undefined가 값을 가지진 안는것같다. 아무튼 null이나 undefined에 어떤 값을 넣으려는 창의적인 시도는 하지말자.

void 연산자

void __ 는 어떠한 값이던 항상 undefined으로 만들어준다.

void는 어떤 식으로 부터 값이 존재하는 곳에 그 값이 undefined가 되어야 좋을 경우에만 사용하자

사실 그럴일이 없긴하지만 의외로 쓸곳이 있을수도 있다.

2.4.3 특수문자

숫자 타입에는 몇 가지 특수한 값이 있다.

The not number, number (Not a Number)

수학 연산시 두 피연산자가 전부 숫자(또는 평범한 숫자로 해석가능한)가 아닐 경우 유요한 숫자가 나올 수 없으므로 결과는 항산 NaN이다
(즉 2/"foo" 과 같은)

NaN은 글자 그대로 숫자가 아님을 나타내지면 이 명칭과 설명이 아주 형편없고 오해의 소지가 다분하다.
'숫자가 아님' 이라는 뜻보다 '유요하지 않은 숫자' '실패한 숫자' 등으로 짓는게 더 명확하다. 왜냐하면 다음 코드를 보면 알수있다.

var a = 2/"foo" // NaN

typeof a ===='number' // true

즉 '숫자아님!'인데 타입은 '숫자'인 것이다(?)

사실 NaN은 결계값(Sentinel Value)의 일종으로 숫자 연산도중 에러가 난상황을 나타낸다

그렇다면 NaN을 체크하는 방법은 무엇이 있을까?

let a =2/"foo"
a==NaN //false
a===NaN // false

// NaN은 어떠한 값이랑도 동등하지 않다(자기자신과도 같지않다)
// 그렇다면 어떤 방법으로 체크해야할까?

isNaN(a) // true 이방법으로 체크하면된다.

// 하지만 이것도 결함이 있는데 이함수는 단지 인자값이 숫자인지 아닌지에대한
// 여부를 평가하는 기능이 전부이다. 때문에 다음과같은 결과가나온다.

var b="foo"
isNaN("b") //true ?

// 때문에 좀더 정확한 Number.isNaN()이 등장한다(ES6)

Number.isNaN("foo")

// false으로 나온다.

개인적인생각 : 여기서 그냥 isNaN과 Number.isNaN()중에 무엇이더 좋은지에대한 생각을 해보았다
그리고 이런 생각 자채가 무의미 하다는 것을 알게 되었다.
(개발자 커뮤니티에서 가르침을 얻었다)
그 이유는 NaN에대한 관점을 달리하면 isNaN과 Number.isNaN() 둘다 유용하게 쓸수 있기 때문이다

  • NaN을 문자그대로 Not a Number(숫자아님)라고 이해하는 관점
    - isNaN()을 쓰는것이 맞다.
    - 단지 숫자가 맞냐 아니냐?라는 관점이면 "foo"라는 값은 숫자가 아니기 때문에 true가 맞다.
  • NaN은 숫자가 연산하는 과정에서 에러가 나서 산출된 값이라는 관점
    -연산관정에서 에러가나는 값만을 인자값으로 주어야 true을 반환하는 Number.isNaN()을 써야한다.
    -때문에 Number.isNaN("foo")에서 "foo"는 연산하는 과정이 없기때문에 false가 나온다.

결론 : 모든 기능들은 옮고 그름이 없고 사용자의 관점에 따라 그 쓰임새가 천차만별 달라질 수 있다 이러한 관점에서 프로그래밍은 결국 언어를 만든 개발자의 철학을 잘이해하고 그 철학에 사용자의 철학을 더하여 더 나은 기능과 코드를 짜는 일이라는 것을 알수있었다.

profile
RN/react.js개발자이며 배운것들을 제가 보기위해서 정리하기 때문에 비속어 오타가 있을수있습니다.

0개의 댓글