JSON 다루기


JSON은 자바스크립트 객체 표기법(JavaScript Object Notation)의 준말로 데이터 전송 형식의 일종이다.
JSON을 다룰때는 JSON.parse()를 사용하는것이 최선책이다.

// 입력되는 JSON 문자열
var jstl = '{"mykey": "myValue"}';

// 안티 패턴
var data = eval('(' + jstl + ')');
console.log(data.mykey);

// 권장안
var data = JSON.parse(jstl);
console.log(data.mykey);


JUI3을 사용하면 다음과 같이 쓸 수 있다.


// 입력되는 JSON 문자열
var jstl = '{"mykey": "myValue"}';

// JUI 인스턴스를 사용하여 문자열을 파싱하고 객체로 변환한다.
YUI().use('json-parse', function(Y){
var data = Y.JSON.parse(jstl);
console.log(data.mykey); // myValue
})


jquery에는 parse.JSON() 이라는 메서드가 있다.


// 입력되는 JSON 문자열
var jstl = '{"mykey": "myValue"}';

var data = jQuery.parseJSON(jstl);
console.log(data.mykey); // 'myValue'


JSON.parse() 메서드의 반대는 JSON.stringify()다. 이 메서드는 객체 또는 배열을 인자로 받아 JSON 문자열로 직렬화 한다.


var dog = {
name : "fido",
dob: new Date(),
legs: [1,2,3,4]
};

var jsonstr = JSON.stringify(dog);
console.log(jsonstr);
// '{"name":"fido","dob":"2019-08-02T07:29:35.248Z","legs":[1,2,3,4]}'


배열 리터럴


자바스크립트의 배열은 이 언어 내 다른 모든 것들과 마찬가지로 객체다. 내장 생성자인 Array()로도 배열을 생성할 수 있지만 리터럴 표기법도 존재하며, 객체 리터럴과 마찬가지로 배열 리터럴 표기법이 더 간단하고 장점이 많다.


// 세 개의 원소를 가지는 배열
// 경고 : 안티패턴이다.
var a = new Array("itary", "bitsy", "spider");

// 위와 똑같은 배열
var a = ["itary", "bitsy", "spider"];

console.log(typeof a); // 배열도 객체이기 때문에 object 가 출력된다.
console.log(a.constructor === Array); // true



배열 생성자의 특이성


new Array(0를 멀리해야 하는 또다른 이유는 이 생성자가 품고 있는 함정을 피하기 위해서다. Array() 생성자에 숫자 하나를 전달할 경우, 이 값은 배열의 첫번째 원소 값이 되는 게 아니라 배열의 길이를 지정한다.

// 한 개의 원소를 가지는 배열
var a = [3];
console.log(a.length); // 1
console.log(a[0]) // 3

// 세개의 원소를 가지는 배열
var a = new Array(3);
console.log(a.length); // 3
console.log(typeof a[0]) // undefined


new Array()에 정수가 아닌 부동소수점을 가지는 수를 전달할 경우 더욱 예상 밖의 결과가 나온다. 부동소수점을 가지는 수는 배열의 길이로 유효한 값이 아니기 때문에 에러가 발생한다.


// 리터럴 사용
var a = [3.14]
console.log(a[0])

var a = new Array(3.14); // error: RangeError: invalid array length
conosle.log(typeof a); // undefined



배열인지 판별하는 방법


if(typeof Array.isArray === "undefined"){
Array.isArray = function(arg){
return Object.prototype.toString.call(arg) === "[object Array]";
}
}


new를 강제하는 패턴


생성자를 호출 할 때 new 를 빼먹게 되면 문법오류나 런타임에러는 발생하지 않지만 논리적인 오류가 생겨 예기치 못한 결과가 나올수 있다.
new를 빼먹으면 생성자 내부의 this가 전역 객체를 가리키게 되기 때문이다.

생성자 내부에 this.menber와 같은 코드가 있을 때 이 생성자를 new 없이 호출하게 되면 실제로는 전역 객체에 member라는 새로운 프로퍼티가 생성된다. 이 프로퍼티는 window.menber 또는 그냥 member를 통해 접근할 수 있다. 이런 동작 방식은 바람직 하지 않다.

// 생성자
function Waffle(){
this.tastes = "yummy";
}

// 새로운 객체
var good_morning = new Waffle();
console.log(typeof good_morning); //'object'
console.log(good_morning.tastes); //'yummy'

// 안티패턴
// 'new'를 빼먹을때
var good_morning = Waffle();
console.log(typeof good_morning); //'object'
console.log(window.tastes); //'yummy'


ECMAScript 5 에서는 이러한 동작 방식의 문제에 대한 해결책으로 스트릭트 모드 에서는 this가 전역 객체를 가리키지 않도록 했다.



명명 규칙


생성자 함수명의 첫글자는 대문자를 쓰고(MyConstructor), 일반적인 함수와 메서드의 첫글자는 소문자를 사용한다(myConstructor).


that 사용


생성자가 항상 생성자로 동작하도록 해주는 패턴을 살펴보자. this에 모든 멤버를 추가하는 대신, that에 모든 멤버를 추가한 후 that를 반환하는 것이다.

function Waffle(){
var that = {};
that.tastes = "yummy";
return that;
}


간단한 객체라면 that이라는 지역변수를 만들 필요도 없이 객체 리터럴을 통해 객체를 반환해도 좋다.


function Waffle(){
return {
tastes : "yummy"
}
}


위의 Waffle() 구현 중 어느 것을 사용해도 호출 방법과 상관없이 항상 객체가 반환된다.


var first = new Waffle(), second = Waffle();
console.log(first.tastes);
console.log(second.tastes);


위 패턴의 문제점도 있다. 프로토타입과의 연결고리를 잃어버리게 된다는 점이다. 즉 Waffle() 프로토타입에 추가한 멤버를 객체에서 사용할 수 없다.



스스로 호출하는 생성자


앞서 설명한 패턴의 문제점을 해결하고 인스턴스 객체에서 프로토타입의 프로퍼티들을 사용할 수 있게 하려면 다음 접근 방법을 고려하면 된다.
생성자 내부에서 this가 해당 생성자의 인스턴스인지를 확인하고 그렇지 않은 경우 new 와 함께 스스로를 재호출 하는 것이다.

function Waffle(){

if(!(this instanceof Waffle)){
return new Waffle();
}

this.tastes = "yummy";

}
Waffle.prototype.wantAnother = true;

// 호출 확인
var first = new Waffle(), second = Waffle();

console.log(first.tastes);
console.log(second.tastes);

console.log(first.wantAnother);
console.log(second.wantAnother);


인스턴스를 판별하는 또다른 범용적인 방법은 생성자 이름을 하드코딩하는 대신 arguments.callee와 비교하는 것이다.


if(!(this instanceof arguments.callee)){
return new arguments.callee();

** ES 5의 스트릭트 모드에서는 허용되지 않는다.

+ Recent posts