자바스크립트 란 언어가 다른 프로그래밍 언어와 다른 이유는 여러가지가 있지만.

기존의 초급자들한테 가장 다가오는것중에 하나는 == 과 === 의 존재이다.

일반적으로 비교연산자 == 은 다른 프로그래밍 언어에서도 자주 쓰이는데. 자바스크립트는 유독 === 이 존재하며

JSHINT, JSLINT, ESLINT 등의 정적 검사도구에서 조차 === 을 권장하고 또는 == 을 안티패턴으로 정의하기도 한다.

== 과 === 의 차이는 그럼 무엇일까?

가장 쉬운 답변은 “===” 은 타입까지 검사한다 ( 스펙 문서에 보면 identically eqaulity 라고 되어있다. ) 라고 할수 있다. 그럼 == 의 로직은 어떻게 동작하는 것일까?

다시 말하면

5 == “5” 가 어떻게 true 가 되는지에 대한 정리를 하고자 한다.

우선  2 개의 값이 서로 다른 타입일 경우에는 타입을 강제로 변환하며,
같은 타입일 경우에는 데이터 타입을 변환 하지 않는다.

즉 숫자와 문자열을 비교할 경우에는 문자열이 숫자로 변환되고 비교 연산이 수행된다.

아래의 예제를 보면 그 사실을 확인 할 수있다.

"0x15" == 21 // true

16진수가 10진수로 변환되며 비교연산이 수행 되는것이다. 즉 문자열->Number()를 사용한것과 같이 수행 됨

Boolean 타입의 경우에는 먼저 숫자로 변환된다음 변환된다.

true 는 1 false 는 0 으로 변환된다.

false == "" //true

위의 예제를 보면 조금더 이해가 쉽다.

그다음  마지막으로 객체의 경우는 다음과 같은 연산을 수행한다.

  1. 해당 객체에 valueOf 메소드가 있다면 valueOf() 호출 비교 연산 수행
    1. valueOf 는 특정 객체의 primitive Value를 리턴하는 함수
  2. valueOf() 메소드가 없다면 toString()을 호출 한후 비교연산 수행

이 연산이 끝난다음  같다면 true로 리턴되는 것이다.

재밌는(?) 예제가 있는데 아래 코드를 보자

var a = {};
a.toString = function(){ 
    return "hello" 
};
var b = "hello";
 
a == b // true;

즉 toString() 메소드가 == 연산에서 호출 되는것을 확인할 수 있다.

이 연산은 + 로 두가지의 값이 더해질테도 이용되는데 + 연산일경우 한쪽이 string이면 다른 한쪽은 강제로 toString()연산후에 값이 만들어진다.

var c = "hello";
var d = {};
d.toString = function(){ 
    return "kazikai"; 
};
c + d // "hellokazikai";

위 코드를 보면 조금 더 이해가 쉽다.

즉 다시 정리하자면

== 는 모든 값을 Number 화 시킨다음 비교

다만  객체의 경우에는 valueOf 메소드를 호출해서 얻은 데이터로 비교 만약에 valueOf 가 없다면 toString()을 호출 하고 비교함

자바스크립트 개발을 하다가 일정 수준 이상이 되면, 코드 가독성 및 더 좋은 패턴에 대해 연구 하게 되고, 널리 쓰이는 패턴을 내 코드에 사용하곤 한다.

물론 책으로도 대부분 접할수가 있으며JSHINT 나, JSLINT와 같은 정적 검사 도구로 체크하여 잘못된 패턴을 지양하고, 좋은 패턴을 사용한다.

그 중  자바스크립트에서 가장 중요한 패턴이라고 알려진 Literal 표기법에 대해서 알아보자.

본 포스팅에서는 우선 객체 선언에서만 다룰 예정이다.

우선 자바스크립트의 DATA Type은 총 7개가 있으며 아래와 같다.

  1. Boolean
  2. Null
  3. Undefined
  4. Number
  5. String
  6. Symbol (ES6 에서 추가)
  7. Object

위 리스트에서 6번까지는 primitive type 이며  Object 는 primitive가 아니다.  여기서 각 type별로 선언하는 여러가지 방법이 있지만 Object는 다음과 같이 주로 선언한다.

var obj1 = {};
var obj2 = new Object();

위 코드에서 obj1 과 obj2는 객체는 동일한 역할을 하게 된다. 즉 아무것도 없는 빈 객체를 생성해서, 향후 프로퍼티 또는 메소드를 추가할 수 있는 객체가 된다.

하지만 위 코드에서 좋은 패턴은 어떤 패턴일까?

주로 대부분의 포스팅이며, 책, 자료에서는 아래와 같은 방식을 좋은 패턴이라고 말한다.

var obj1 = {}; //good pattern

위 코드를 바로 literal 표기법이라고 한다. 간단하게 객체를 선언할 수 있으며 아래와 같은 코드에서는 가독성 또한 좋아진다.

//객체 생성과 할당 
var obj1 = {
  a: 1,
  b: 2
};
//객체 생성한 후 할당 
var obj2 = new Object();
obj2.a = 1;
obj2.b = 2;

그렇다면 단순히 가독성을 위해서 {} 를 new Object 에 비해 권장 하는 것일까?

이제 본론으로 들어가자

이 포스팅을 작성하면서, 갖고 있던 근원적인 물음은 다음과 같다.

1. {} 과  new Object()는  동일한 객체를 생성할까?

우선 Literal 기법과 new 기법으로 생성된 객체는 동일한 객체이다. ( 의미적으로 동일하다는 말이다. 참고로 String 은 다르다. ). 즉 같다. 

[참고]

var str1 = "";
var str2 = new String();
console.log( typeof str1 ); // "string"
console.log( typeof str2 ); // "object"

위 코드에서  str1 과 str2 는 다르다. str1 은 type이 string 이지만 str2는 object 이다.

[/참고]

1번의 물음이 해결되고 나서 다시 궁금한점이 생겼다.

2. 그렇다면 {}를 권장하는 이유는 무엇인가? ( 단순히 가독성때문에?)

사실 2번에 대한 이유는 몇가지 알고있었다. (대체적으로 가독성, 속도 정도 였고,  자바스크립트에서 내장함수가 override  되는 버그(?) )

하지만 뭔가 다른 이유가 있을 것이라 생각하며 문제를 하나씩 찾아보았다.

첫번째로 가독성이다. 

Literal 기법이 대체적으로 더 짧고 직관적이며 객체를 생성하기도 더욱 용이하다. 위에서 살펴 보았듯이 생성과 할당에 더 적합하다. 또한 가장 기본적인 데이터를 선언하는데 있어서 new 표현을 덜 쓰면서, 가독성도 더 좋아진다.

두번째는 속도다. 

이미 여러가지 실험을 통해 Literal기법이 속도가 더 빠르다는것이 증명되었다.  ( 약 12.14% 빠르다 )

http://jsperf.com/new-array-vs-literal/26

하지만 사실상 미미하며, 정말 복잡도가 높은 어플리케이션을 개발할 경우만 필요할 수도 있다고 생각한다. ( 개인적 의견 ) . 이전 브라우저에서는 많이 차이가 있었지만, 최근에는 그 격차가 많이 좁혀진게 아닐까 생각한다.

* 속도가 왜 빠른지는 나중 포스팅에서 다뤄보자.. 중요하다. 

마지막으로 세벗째는 Overriden에 따른 예방이다. 

우선 자바스크립트는 기본 함수 조차도 Overriden이 된다.  overriden이란 재정의란 의미로 Object 도 어떻게 보면 자바스크립트에서 함수이기도 한다. 하지만 이 함수를 재정의 할수 있다. 예제를 한번 만들어보자

Object = function(){ 
 alert("재정의"); 
};
var obj1 = new Object(); //alert 발생

즉 Object 란  내장함수 조차도 재정의 되어서 전혀 예상치 못한 결과를 초래할 수 있다.

이렇게 literal기법으로 선언 하는것이 더욱 효과적이며 해당 근거는 위에 3가지 정도로 요약할 수 있다.

별거 아닌거지만, 가장 기본적이며, 향후에 Array, String, Number 에대해서도 다뤄볼 예정이다. ( String은 또 다르다. )

 

배열 메소드 들중에.. 평소에 잘 사용하지 않지만, 사용하면 생산성이 많이 올라가는 메소드 들이다.

하지만 다시 리마인드 하는 의미로 정리하면, 도움이 될것 같다. 익숙한놈도 있고.. 초기에 JS 공부할때 알아뒀지만, 한번도 안써봤던,,(reduce) 같은 놈들은 다시 보니 어색 하기도 하고. 이번기회에 정리를 해보자

아래는 이 포스팅의 원문이 되는 블로그

http://colintoh.com/blog/5-array-methods-that-you-should-use-today?utm_source=javascriptweekly&utm_medium=email

 

1. 배열에서특정값이 있는지 찾을때는 indexOf 사용해라 

대부분의 배열에서 indexOf 를 사용 하지 않으면, for loop 를 돌려서 찾을수 밖에 없다. 즉 아래와 같은 코드를 사용 하게 되는데.

var isExist =false;
for( var i = 0; max = array.length; i += 1 ) {
 if( array[i] === "특정값" ){
   isExist = true;
 }
}

위와 같은 코드는 아래와 같이 간단하게 사용할 수 있다.

var isExist = (array.indexOf(“특정값”)!== -1 )

즉  간단하게 위의 for loop 를 한줄로 표현할 수 있으며, 이부분이 생산성이나, 코드 가독성에 도 옳은 영향을 끼친다.

2. filter 사용해보세요:)

이건.. JSON 오브젝트로 이루어진 배열중에 특정 값만 filter 시킬때 유용하다.

var arr = [    
  {"name":"apple", "count": 2},    
  {"name":"orange", "count": 5},    
  {"name":"pear", "count": 3},    
  {"name":"orange", "count": 16}
];    
var newArr = arr.filter(function(item){    
  return item.name === "orange";
});  
console.log("Filter results:",newArr);

위 값의 newArr 은 name이 orange 인 놈만 필터 되서 나온다.

3. forEach()쓰세요

사실 개인적으로 for 루프가 더 성능 향상에 좋다고 해서..( 자바스크립트 성능 최적화에 나온다. ).for 로 풀어서 쓰는데  1ms 도 차이 안나니 그냥 forEach를 쓰라고 가이드 한다.

사용법은 아래와 같다.

var array = [1,2,3,4,5];
array.forEach( function( v, i ){
  if( v === 3 ){
    console.log( v + ":" + i); // 3:2 가 나온다.
  }
});

4. map을 잘 활용하자. 

이전에 jsperf 에서 map이 forEach 보다 더 성능이 빨라서. 개인적으로 array에서 map을 주로 써왔다. 하지만 … map과 forEach는 용도가 미세하게 다른데.. map은 각 루프에서return을 할수있는 것이 특징이다.

( return된 결과의 동일한 배열을 원하는것이 아니라면 forEach가 더 적합하다. )

즉 map을 사용하면, 리턴값으로 같은 길이의 배열이 나오게 된다.

예를들어 …

var a = [1,2,3,4,5];
var b = a.forEach( function(v, i){ console.log(v); return v+1;}});
var c = a.map( function(v, i){ console.log(v); return v+1;});

를 실행해보면차이점이 다르다.  b는 undefined 가 나오며 c 는 [2,3,4,5,6] 이라는 배열이 나온다.즉 배열을 가지고, 연산을 하고 길이가 같은 배열로 결과를 리턴받고 싶을때는 map을 쓰는것이 훨씬 유리하다.

forEach와는 용도가 서로 다르다는것을 기억하자

마지막으로 5..

5.reduce!!  사용하자 

이놈은.. 인자를 어떻게 주냐에 따라 용도가 달라진다.

array.reduce(f,n)
var a= [1,2,3,4,5] //f는 함수 n은 두번째 인자 라고 가정
n이 없을경우 array.reduce(f);를 살펴 보자 
f의 
(0) iteration 
- 첫번째 인자 : 1
- 두번째 인자 : 2
(1) iteration
- 첫번째 인자 : 1,2
- 두번째 인자 : 3
(2) iteration
- 첫번째 인자 : 1,2,3
- 두번째 인자 : 4
(3) iteration
- 첫번째 인자 : 1,2,3,4
- 두번째 인자 : 5
로 나오게 된다.
즉 f 의 인자가 f( a,b,c,d) 라면
a=이전값
b= 현재값
c= 인덱스
d= 배열

로 생각하면 된다.

하지만 reduce 메소드를 불러올때  n을 주게 되면, f의 첫번째 인자가 n이 되게 되는데, 즉 이전초기값이 n으로 대체 된다. 

var a= ["a","b","c","d","e","a","b","a","c","c","c"];
var b = a.reduce(function(x,y){
  console.log("x:", x);
  console.log("y:", y);
  x[y] = ++x[y]|| 1;
  return x;
},{});
console.log(b);

위 예제를 돌려보면 B 는 최종적으로

Object {a: 3, b: 2, c: 4, d: 1, e: 1}

로 리턴된다. 

설명한 5개의 메소드들은  사용하면 개발 생산성 및 가독성이 좋아질 것 같다.