— javascript — 3 min read
1console.log(typeof null); // object2console.log(typeof function(){}); // function 하지만 실제로는 object 의 하위 타입이다.3console.log(typeof {}); // object4console.log(typeof []); // object
유일하게 null 만 typeof 값이 object 로 나오는 버그가 있다.
배열과 함수는 객체다. 배열은 숫자 index 를 가지며, length 프로퍼티가 자동으로 관리되는 추가 특성을 가진 객체일 뿐이며 함수는 내부 프로퍼티 [[Call]] 을 통해서 호출이 가능한 객체일 뿐이다.
undefined 와 not defined 는 다르다.
undefined: 접근가능한 스코프에 변수가 선언되었으나 현재 아무런 값도 할당되지 않은 상태
not defined: 접근가능한 스코프에 변수 자체가 선언조차 되지 않은 상태
1var a;23console.log(a); // undefined4console.log(b); // not defined
typeof 를 이용해서 특정 변수나 함수가 정의되어 있는지 판별할 때 도움이 되긴 한다.
1if (typeof DEBUG !== 'undefined') {2 console.log('디버깅을 시작합니다.');3}
1var a = 'foo';2var b = ['f','o','o'];34// length 프로퍼티5console.log(a.length);6console.log(b.length);78// indexOf() 메소드9console.log(a.indexOf('f'));10console.log(b.indexOf('f'));1112// concat() 메소드13console.log(a.concat('bar'));14console.log(b.concat(['b','a','r']));1516// 값을 변경할 경우17a[1] = 'f';18b[1] = 'f';1920console.log(a); // a 는 불변값21console.log(b); // b 는 가변값2223var c = a.toUpperCase();24console.log(a === c);2526b.push('!!');27console.log(b);
toFixed()
함수를 쓰기 위해서는 도트연산자(.) 가 2개 필요하다. 첫 번째 도트연산자를 소수점으로 계산하기 때문이다.1console.log(42.toFixed(3)); // Syntax Error2console.log(42..toFixed(3)); // 42.000
신기하게도 0.1 + 0.2 === 0.3
은 false 다. 0.1 + 0.2 가 정확하게 0.30000000000000004 라고 한다.
1console.log(0.1 + 0.2 === 0.3);2console.log(0.1 + 0.2);
이진 부동 소수점 숫자의 부작용으로 알려진 것인데, 대응책은 ES6에서 Number.EPSILON 으로 오차값을 미리 정의해놓았다.
1Math.abs(n1 - n2) < Number.EPSILON; // 미세한 오차보다 작은지를 통해 비교할 수 있다.
ES6부터 Number.isInteger()
로 어떤 값의 정수 여부를 확인할 수 있다.
NaN 은 숫자가 아니다(Not A Number) 라는 뜻이지만 typeof 로 확인해보면 'number' 를 가리킨다.
isNaN()
은 숫자가 아닌 다른 타입의 정상적인 값도 true 를 가리킨다. ES6 에서는 이를 보완한 Number.isNaN()
을 쓸 수 있다.
0으로 값을 나누면 에러가 아닌 Infinity(Number.POSITIVE_INFINITY) 값이 나온다. 음수값을 0으로 나누면 Number.NEGATIVE_INFINITY 가 나온다.
0과 -0 은 확실하게 구분하기 어렵다. -0 은 값의 부호로 방향을 나타내야 하는 프로그램에서 주로 사용된다.
ES6 에서는 특이한 동등비교를 할 때를 위해 Object.is()
를 만들었다. 잡다한 예외를 걱정하지 않아도 동등한지 비교할 수 있다.
원시값을 레퍼런스 형태로 넘겨도 레퍼런스공유가 이뤄지지 않는다.
1function foo(x) {2 x = x + 1;3}45var a = 2;6var b = new Number(a);78foo(b); 9console.log(b); // 2
1var a = new String('abc');2console.log(typeof a); // String 이 아닌 object3console.log(a instanceof String) // true4console.log(Object.prototype.toString.call(a)); // [object String]
1console.log(Object.prototype.toString.call([1,2,3]));2console.log(Object.prototype.toString.call(/regex/i));3console.log(Object.prototype.toString.call(null));4console.log(Object.prototype.toString.call(undefined));
1var mySymbol = Symbol('my own symbol');2console.log(mySymbol);3console.log(mySymbol.toString());4console.log(typeof mySymbol);56var a = {};7a[mySymbol] = 'foobar';89console.log(Object.getOwnPropertySymbols(a));
1var a = 42;2var b = a + ''; // 암시적3var c = String(a); // 명시적
1var a = {2 b: 'b',3 c: 'c',4 d: undefined,5 f: function() {},6 s: Symbol('symbol')7};89//a.a = a; // 에러 발생1011console.log(JSON.stringify(a));
.toJSON()
에 문자열화 할 값들을 정의한다. 정의만 할 뿐 문자열화는 JSON.stringify()
가 처리한다.JSON.stringify()
에는 2, 3번째 매개변수가 있다. MDN1var a = {2 valueOf: function () {3 return '42';4 }5};67var b = {8 toString: function() {9 return '42';10 }11};1213var c = [4, 2];14c.toString = function() {15 return this.join('');16};1718console.log(Number(a)); // 4219console.log(Number(b)); // 4220console.log(Number(c)); // 4221console.log(Number('')); // 022console.log(Number([])); // 023console.log(Number(['abc'])); // NaN
42.toString()
은 박싱 과정이 들어가기 때문에 '명시적으로, 암시적인' 작동이다.
+'32'
는 숫자로 명시적 강제변환한다.
~ (틸드) 연산자는 32비트 숫자로 강제변환 후 NOT 연산을 한다. 각 비트를 거꾸로 뒤집는다.
~x 는 -(x+1) 과 같다. 이 점을 이용해서 문자열이 다른 문자열에 포함되어 있는지 검증할 때 더 깔끔한 코드를 만들 수 있다.
1var a = 'acdefg';2if (a.indexOf('b') === -1) {3 console.log('깔끔하지 않은 코드다. Leaky Abstraction, 즉 경계 값 -1을 실패로 정해버렸다.');4}56if (~a.indexOf('b')) {7 console.log('b가 a에 있을 경우 들어온다. ~a.indexOf("b") 값이 0이 아니기 때문이다.');8} else {9 console.log('b가 a에 없을 경우 -1을 반환하고 -(-1 +1) = 0 이므로 falsy 값인 0이 나와 if 문을 들어가지 않는다.'); 10}
+ 연산의 한 쪽 피연산자가 문자열이면 + 는 문자열 붙이기 연산을 한다.
1var a = {2valueOf: function() {3 return 42;4},5toString: function() {6 return 2;7}8};910console.log(a + ''); // 빈 문자열과 더할 경우는 valueOf() 를 호출한 후 문자열 붙이기를 한다.11console.log(String(a)); // String() 은 toString 을 호출할 뿐이다.
&&, || 연산자는 우선 첫 번째 피연산자의 불리언 값을 평가한다. 피연산자가 불리언이 아니면 먼저 ToBoolean 로 강제변환 후 평가를 계속한다.
Symbol 은 암시적 강제변환이 안된다.
1var s1 = Symbol('좋아');2console.log(String(s1));34var s2 = Symbol('구려');5console.log(s2 + '');
자바스크립트의 동등 비교 (느슨한 비교(==), 엄격한 비교(===)) 관련 테이블 참고
a || b && c
는 a || (b && c)
가 된다.try finally
문에서 try 문 안에서 return 을 하면 finally 가 먼저 실행되고 return 된다.1function foo() {2 try {3 return 42;4 } finally {5 console.log('finally');6 }7 console.log('never occurred');8}910console.log(foo());
1function foo() {2 try {3 return 42;4 } finally {5 6 }7}89function bar() {10 try {11 return 42;12 } finally {13 return;14 }15}1617function baz() {18 try {19 return 42;20 } finally {21 return 'Hello';22 }23}2425console.log(foo()); // 4226console.log(bar()); // undefined27console.log(baz()); // "Hello"