Javascript this

1. What is ‘this’?

마지막으로 JS의 ‘this’에 대해서 이야기 해 보고자 한다. 많은 사람들이 JS에서 this를 어려워하는 것은 기본적으로 다른 class/instance개념 기반 언어들의 개념으로 this를 생각하기 때문이다.

var MyFunction = function() {
    this.a = 1;
}
 
> MyFunction.a
undefined

기존 class/instance형 언어의 개념으로 생각해 보면 MyFunction은 ‘선언’만 된 것이고 MyFunction은 생성이 안된 클래스로 생각된다. (아니라는 것은 첫번째 글에서 설명했다. MyFunction은 엄연한 이 상태로 객체이다.)

앞에서 MyFunction은 저 상태로 객체가 생성은 되지만 함수가 호출은 되지 않는다고 했다. 그렇다면 혹시 MyFunction(); 으로 함수를 호출하면 객체가 생성될지도 모르겠다.

var MyFunction = function() {
    this.a = 1;
}
MyFunction();
 
> MyFunction.a
undefined       // oops.. it is still undefined...

하지만 MyFunction을 호출하더라도 (분명히 호출했다) MyFunction에 a라는 프로퍼티는 존재하지 않는다. 그렇다면 도대체 a는 어디로 간 것일까.

위와 같은 사고의 흐름이 흔히 JS에서 this를 접하는 경우에 겪게되는 사항이다. 일단 사고의 방식을 JS에서는 바꾸어야 한다. 우선 다음의 3가지만 기억하자.

  • JS에서 this는 어떤 객체를 가르키는 것은 맞다.
  • JS에서 this는 함수 안에서만 의미를 가진다.
  • 하지만 this는 어떤 함수에 종속되는 값이 아니며, this가 어떤 값을 가지는지는 그 함수가 ’호출될 때’ 결정된다. (이게 중요한 개념이다!)

2. Call-site

콜스택(call-stack)은 많이 들어보았지만 콜사이트(call-site)는 생소한 사람들도 있을 것이다. call-site는 간단한 개념으로 해당 콜스택에 들어오기 전의 call을 한 곳을 말한다. 다음의 예를 보자

function A() {
    console.log("Hello, I am A");
    B();    // call-site for B() is A()
}

function B() {
    console.log("Hello, I am B");
    C();    // call-site for C() is B()
}

function C() {
    console.log("Hello, I am C");
}

A();    // what is call-site for A(); ?

함수 A는 B를, B는 C를 부른다. B가 호출될 때의 즉, B의 call-stack에 들어와 있을 때의 call-site는 A의 호출지점이 된다. 같은 식으로 C에 들어와 있을 때는 B가 call-site가 될 것이다. 어떤 함수의 this는 다른 조건에 해당하지 않는다면 (하지만 언제나 그렇듯이 이 조건이 매우 복잡해지는게 문제이다) 해당 함수가 호출될 때의 call-site의 값을 가진다. 이것을 기본 바인딩 (Default Binding)이라고 한다. 그렇다면 위에서 A가 호출될 때의 call-site는 무엇일까?

3. Default Binding

위의 질문에 답을 찾기 위해 다음의 코드를 실행해 보자.

function foo() {
    console.log(this.a);
}
foo();      // undefined

var a = 2;
foo();      // 2

처음 foo()함수를 실행시킬 때는 this.a 는 undefined였다. 전역 변수로 a = 2를 선언한 뒤에 다시 foo()를 실행하니 값이 2임을 알 수 있다. foo()는 전역 scope에서 실행시켰기 때문에 call-site는 전역객체가 되는 것이다. 이에 foo()가 실행될 때 this는 전역객체가 된다.

만일 strict mode에서 실행중이라면 this는 전역객체가 되지 않고 TypeError가 발생한다.

이와 같이 다른 조건이 없다면 어떤 함수가 ’호출될 때’ this는 해당 함수 호출의 call-site (함수라면 call-site의 this값이라고도 생각할 수 있다.)의 값으로 셋팅된다. 다시말해 this는 함수에 고정되어 있는 값이 아니라 함수가 호출될 때 마다 그때그때 바뀔 수 있는 값이다.

하지만 this가 결정되는 방법은 이 Default Binding말고도 3가지가 더 있어 다음과 같은 4가지 경우가 있다.

  • Default Binding
  • Implicit Binding
  • Explicit Binding
  • ‘new’ Binding

이 총 4가지의 우선 순위에 따라 최종적으로 this가 어떻게 결정될지가 정해진다.

4. Implicit Binding

그런데 call-site가 어떤 함수의 call 위치가 아니라 객체 자체가 될 수도 있다. 다음의 예를 보자.

function foo() {
    console.log(this.a);
}

var obj = {
    a:3, 
    foo: foo
}

obj.foo();          // 3

위에서 객체 obj는 함수 foo를 그 자신의 foo라는 이름의 프로퍼티로 가지고 있다. 이 때 obj.foo() 호출은 obj라는 객체를 call-site의 context로 가지게 된다. 이 경우 foo의 this는 해당 context가 되며 이를 암묵적 바인딩(Implicit Binding)이라고 한다.

하지만 매우 실수하기 쉬운 함정이 여기에는 하나가 있다. 역시 다음의 코드를 보자.

function foo() {
    console.log(this.a);
}

var obj = {
    a:3, 
    foo: foo
}

var bar = obj.foo;

bar();          // undefined???

위의 코드에서 bar()를 실행하면 기대와 달리 undefined가 나오는 것을 볼 수 있다. 자세히 보면 obj.foo라고 표시를 했지만 이 값은 그냥 함수 foo를 가리키는 것일 뿐이다. 따라서 다른 변수 bar에 obj.foo를 할당하는 것은 그냥 함수 foo의 또 다른 레퍼런스를 할당하는 것 이상도 이하도 아니다. 다시 말하지만 this가 결정되는 것은 해당 함수가 ’호출되는 순간’이다. obj.foo는 그냥 함수의 레퍼런스, obj.foo()는 obj를 컨텍스트로 하는 ‘함수의 호출’로 분명히 둘은 다르다. 이와 같은 실수는 실제로 복잡한 코드를 작성하다 보면 매우 쉽게 나올 수 있다. 이를 Implicit Lost라고도 한다.

Implicit Lost가 발생하는 대표적인 경우가 함수를 callback함수의 인자로 넘겼을 때다. 위의 obj.foo를 다음과 같이 setTimeout에 인자로 넘긴다고 생각해 보자.

setTimeout(obj.foo, 100)

콜백으로 넘긴 obj.foo가 실행될 때 this가 obj로 셋팅될거라 기대하기 쉽지만 콜백으로 넘긴 obj.foo는 그냥 foo함수의 레퍼런스일 뿐이다. 해당 콜백이 불릴때 this는 그냥 전역객체가 된다. 심지어 콜백함수를 받는 많은 함수들 중에는 자기가 맘대로 callback의 this를 강제로 셋팅하는 경우도 많기 때문에 항상 레퍼런스를 잘 체크해야 한다.

5. Explicit Binding

this를 사용할 때 생기는 문제의 대부분은 내가 전혀 기대하지 않은 값으로 this가 셋팅되는 경우에 발생한다. 그래서 아예 함수를 호출할 때 this를 명시적으로 정해주는 방법이 있다. 이는 함수 call()과 apply()를 통해 제공된다.

function foo() {
    console.log(this.a);
}

var obj = {
    a:3, 
}

foo.call(obj);      // 2

위의 예에서 사용하는 것을 보면 알 수 있듯이 call()과 apply()는 Function.prototype에 정의된 함수이다. 둘 다 인자로 받은 객체를 해당 함수의 호출에서 this로 셋팅한다.

call과 apply는 완전히 같은 함수로 인자를 전달하는 방식만 다르다. 둘 다 첫번째 인자로 this로 셋팅할 객체값을 전달하고, call은 두번째 이후 인자를 원래 함수의 인자로 순서대로 전달하고 apply는 원래 함수의 모든 인자를 하나의 배열에 넣어서 전달한다.

foo.call(obj, arg1, arg2, arg3);
foo.apply(obj, args); // args is an Array

하지만 call과 apply만으로는 해결 못하는 문제가 있다. 앞에서 보았던 setTimeout에 콜백으로 함수를 넘길때가 대표적인 예이다. 콜백으로는 함수의 레퍼런스를 넘길 수 있지만 함수의 호출(call과 apply는 함수의 호출이 필요하다.)을 넘길 수는 없다.

이에 아예 함수 자체에 특정 객체를 this로 bind해 버리는 방법이 필요해졌다. 이는 Function.prototype.bind()함수로 가능하다. 이를 Hard Binding이라고 한다. bind() 함수의 동작을 매우 간략하게 (실제로는 훨씬 복잡하지만) 표현하면 다음의 코드와 같다.

function bind(fn, obj) {
   return function() {
        return fn.apply(obj, arguments);
    };
}

bind()함수는 인자로 받은 객체를 call이나 apply를 이용하여 강제로 해당 call의 this로 할당한 ’함수를 리턴한다.’ JS에서 어떤 함수가 다른 ‘함수’를 리턴하는 코드를 많이 볼 수 있다. 이는 대부분 해당 함수의 context를 고정하거나 조작하기 위한 경우가 많다.

Hard Binding을 사용하면 앞에서와 같이 Implicit Lost가 발생하는 경우를 막을 수 있다.

function foo() {
    console.log(this.a);
}

var obj = {
    a:4, 
}

var bar = foo.bind(obj);

bar();  // 4

6. new Binding

이는 이전 글에서 말했던 바와 같이 생성자 함수로 new를 통해 새로운 객체를 만들때의 binding을 이야기 한다. 이 경우 해당 생성자의 call에서 this는 언제나 새로 new로 생성되는 객체로 설정된다. 다음의 코드에서 확인할 수 있다.

function foo(a) {
    this.a = a;
}

var bar = new foo(2);

bar.a;      // 2

7. Binding Order

실제로는 위의 모든 binding의 경우가 뒤섞일 수 있다. 이 경우에는 다음의 순서로 this가 결정된다.

  • 1) 모든 것에 우선해 new Binding이 이긴다. 만일 함수가 new로 새로운 객체를 생성했으면 해당 생성자의 call에서 this는 바로 생성된 객체이다.
  • 2) 그 다음 Explicit Binding이 이긴다. 어떤 함수가 call과 apply를 통해 실행되었으면 인자로 넘어간 객체가 this이다.
  • 3) 그 다음은 Implicit Binding이다. (대신 Implicit Lost가 발생하지는 않는지 주의해야 한다.)
  • 4) 위의 모든 경우가 아닐때 Default Binding이 적용된다.

다음의 예를 보면 확인할 수 있다.

function foo(a) {
    this.a = a;
}

var obj1 = {a: 2};

var bar = foo.bind(obj1);
var baz = new bar(3);

console.log(obj1.a);    // 2
console.log(baz.a);     //3

8. this in the Arrow Function

한가지 마지막으로 언급하지 않을 수 없는 것이 ES6에서 새로 도입된 Arrow Function이다. Arrow Function은 일종의 anonymous function을 선언하는 방법으로 생각할 수 있다. 인자를 ()안에 넣고 그 뒤에 => 를 쓴 다음 {}로 코드블럭을 쓸 수 있다. Arrow Function은 콜백함수를 선언할 때 편리하게 쓰일 수 있는데 일반적인 JS함수들과 달리 Arrow Function의 this는 Lexical scope, 즉 Arrow Function이 선언될 때의 scope를 따르기 때문이다. 다음의 예를 보자.

function foo() {
    return (a) => {
        console.log(this.a);
    }
}

var obj1 = { a:2 };
var obj2 = { a:3 };

var bar = foo.call(obj1);
bar.call(obj2);     // 2, not 3!

위에서 보다시피 Explicit Binding 시도(foo.call(obj1))에도 불구하고 bar는 Arrow Function이기 때문에 항상 Lexical scope로 binding됨을 알 수 있다. (foo가 call()함수를 통해 호출될 때의 call-site를 this로 가지고 있다.)

이는 콜백함수에서 매우 편리하다. 다음의 예는 ES6 이전에 callback에서 컨텍스트를 유지하기 위해 쓰던 방법이다.

function foo() {
    var self = this;        // capture this with self
    setTimeout(function() {
        console.log(self.a);
    }, 1000);
}
var obj1 = { a:2 };

foo.call(obj1);         // 2

별도의 변수 self를 선언해 현재의 this를 캡쳐한 후 이를 closure를 이용해 콜백 함수에서 사용하는 것을 볼 수 있다. 이는 Arrow Function을 쓰면 다음과 같이 간단히 쓸 수 있다.

function foo() {
    setTimeout(() => {
        console.log(this.a);        // this is lexically captured
    }, 1000);
}
var obj1 = { a:2 };

foo.call(obj1);         // 2

여기까지가 JS에서 this에 대한 이야기였다. 지금까지 이야기한 JS의 Object, Prototype, this 에 대해 이해를 확실히 해 두면 많은 부분에서 JS의 구조가 명확해 질 것이라고 생각한다. 간만에 기술적인 글을 쓰려니 힘들긴 하지만 나름 즐거운 경험이었다.

Javascript Prototype

앞의 글에서는 Javascript에서 일반적인 객체 개념에 대해 알아보았다. 다시 정리하자면 JS에는 일반적인 class기반 언어에서 이야기하는 class/instance관계가 존재하지 않는다. 모든 것은 object로서 존재한다. JS에서 함수가 new 연산자에 의해 객체 생성에 쓰이는 경우 그 함수를 생성자(constructor)라고 한다. (생성자라는게 따로 존재하는게 아니다.) 따라서 JS의 함수는 객체를 설계하는 class같은 개념이 ’아니다.’

앞의 글에서 new가 함수에 사용되어 객체가 생성되는 경우 다음의 4단계의 동작이 일어난다고 했다.

  • 1) 새로운 객체가 생성된다.
  • 2) 새로 생성된 객체의 [[prototype]] 이 링크된다.
  • 3) 생성자함수의 this가 새로 생성된 객체로 (bind)되어 생성자가 호출된다.
  • 4) 새로 생성된 객체가 리턴된다 (new의 리턴값으로). 단, 한가지 예외가 있는데 해당 생성자가 다른 별도의 객체를 리턴하는 경우다. 이 경우는 새로 생성된 객체는 그냥 버려지고 생성자가 리턴하는 객체가 new의 리턴값이 된다.

이 글에서는 이 중 많은 사람들을 혼동으로 빠트리는 [[prototype]]에 대해서 이야기 해 보겠다.

1. Prototype

JS에서 prototype은 매우 중요하고 핵심적인 내용이다. 그런데 많은 사람들이 이에 대해 힘들어하는 것은 너무나 서로 다른 개념을 모두 ‘prototype’ 이라고 말하는 경우가 많기 때문이다. JS에서 prototype이라고 보통 불리는 것들은 정확히는 다음과 같이 3가지의 서로 다른 개념이 있다. (용어는 완전히 일치하지는 않는다.)

  • Prototype Object (프로토타입 객체)
  • Prototype Link (프로토타입 링크)
  • Prototype Property (프로토타입 프로퍼티)

위 3가지를 명확하게 구분할 수 있어야 JS에서 prototype을 이야기 할 때 혼동을 피할 수 있다.

모든 JS의 객체는 자신이 생성될 때 그 근본이 되는 객체가 있다. 이것이 Prototype Object이다. 일반적으로 그냥 ‘프로토타입’이라고 말할 때는 바로 이 Prototype Object를 의미한다. (보통 ‘어떤 객체의 프로토타입’이라고 말한다.) 모든 객체의 프로토타입은 궁극적으로는 Object.prototype 이라는 객체이다. (그냥 Object가 아니라 Object.prototype임에 유의해야 한다.)

new가 실행될 때의 4단계에서 언급되는 [[prototype]]은 Prototype Link를 의미한다. 일반적인 객체에서는 각 객체의 __proto__ (’_’이 앞 뒤 각각 2개이다.) 프로퍼티로 접근할 수도 있지만 표준이 아니기 때문에 지원안하는 환경이 있을 수 있다. 경우에 따라 [[prototype]]와 proto 를 혼재해 사용하는 경우도 많다.

2. 함수객체의 생성

다음과 같이 MyFunction의 코드가 있다고 가정하자.

var MyFunction = function() {
    this.a = 1;
}

다시말하지만 이건 ‘선언(declaration)이 아니다.’ 위의 코드로도 멀쩡하게 MyFunction이라는 함수 객체가 생성된다.

> MyFunction
[Function: MyFunction]

그럼 함수 객체가 생성되었다고 했으니 a값은 1로 셋팅되었나 확인해 보자

> MyFunction.a
undefined

엇… 그런데 MyFunction이라는 객체에는 a 라는 프로퍼티는 존재하지 않는 것을 알 수 있다.

그럼 도대체 위의 코드로 생성된 것은 무엇인가? 이는 ‘Function.prototype’이라는 객체를 프로토타입으로 해서 생성된 다른 함수 객체이다. 이제부터 이 함수 객체의 몇가지 중요한 개념을 이야기 해 보겠다.

  • JS에서 생성된 모든 객체는 ‘Prototype Link’를 가진다. 보통 [[prototype]]로 표시되는 녀석이다.
  • JS에서 생성된 모든 객체는 그 객체의 생성과 연관되는 ‘Prototype Object’가 존재한다. 이 Prototype Object를 가리키는 것(일종의 포인터로 생각하면 된다.)이 Prototype Link ( [[prototype]] )이다. 이 [[prototype]]도 그 객체의 프로퍼티이지만 뒤의 함수 객체의 Prototype Property와 혼동을 피하기 위해 명확하게 [[prototype]] 또는 Prototype Link라고 불러주는게 좋다.
  • JS의 객체중 ’함수 객체’는 특이한 프로퍼티를 하나 가지는데 그 이름이 ‘prototype’이다. (이게 많은 혼란의 근본이다. 위의 Function.prototype도 이 일종이다. – ‘Function’ 자체도 하나의 함수이다.) 이 Prototype Property는 해당 함수의 ‘Function Prototype Object’를 가리킨다.

위에서 MyFunction로 함수 객체는 생성이 되었지만 해당 함수는 호출(call)되지 않는다. 함수를 호출하려면 명백하게 함수이름 뒤에 ‘()’를 써서 호출을 해야 한다.

위의 설명을 MyFunction 예제를 바탕으로 무슨 일이 일어났는지 다시 설명하면 다음과 같다.

  • 일반적인 다른 언어의 ‘선언부(declaration)’로 ’보이는’ 코드는 실제로 MyFunction 이라고 하는 ’함수 객체’를 생성한다. 함수 객체는 일반적인 객체와 같지만 몇가지 다른 특징을 가지는 객체이다.
  • MyFunction은 다른 일반 객체와 같이 자신의 생성시 바탕이 되는 Prototype Object가 있다. 이는 역시 다른 객체와 같이 MyFunction의 Property Link, 즉 [[prototype]]이 가리키는 객체이다. MyFunction의 [[prototype]]가 가리키는 값은 (즉, MyFunction의 프로토타입은) Function.prototype이라는 객체이다.
  • 그런데 함수 객체는 일반 객체와 달리 이름이 ’prototype’이라는 프로퍼티가 존재한다. (이게 일반적으로 사람들이 혼동을 일으키게 만든다. 이를 명확하게 하기 위해 Prototype Property라고 구분해서 말하기도 한다.
  • 그럼 이 MyFunction의 prototype이라는 프로퍼티, 즉, MyFunction.prototype 이라는 프로토타입 프로퍼티가 가리키는 값은 무었인가. 이 역시 하나의 객체이다. 다만 이는 MyFunction의 프로토타입과는 다른 별도의 객체이다. MyFunction.prototype은 해당 함수가 (그래서 함수 객체에만 존재한다.) 생성자로 쓰일 때 (new로 호출될 때) 생성 될 객체의 기반이 될, 즉 그 생성되는 객체의 프로토타입이 될 객체이다.

3. new를 통한 객체 생성의 예

다시 다음의 코드가 실행된다고 할 때, (다시 말하지만 해당 코드는 실행되지만 MyFunction은 호출이 되지 않는다.)

var MyFunction = function() {
    this.a = 1;
}

메모리에는 다음과 같은 상황이 된다.

함수 객체의 Prototype Property(가 가리키는 객체)에는 특별하게 constructor라는 프로퍼티가 있는데 이는 자신을 활용할 생성자 함수를 다시 가리키고 있다.

이제 다음과 같이 MyFunction으로 new를 이용해 새로운 객체를 생성해 보자.

var MyFunction = function() {
    this.a = 1;
}
var mine = new MyFunction();

>mine.a 
1

이렇게 new를 사용할 때 다음과 같은 과정이 벌어진다.

  • 새로운 객체가 하나 생성된다.
  • 새로운 객체의 프로토타입이 ( = [[prototype]] 의 값이) MyFunction.prototype으로 설정된다. (MyFunction이 아니라 MyFunction.prototype임을 주의해야 한다.)
  • 이 객체의 생성자(MyFunction)의 this가 지금 새로 생성된 객체로 설정되어 실행된다. 이 때 새로운 객체에는 a라는 프로퍼티가 생성된다.
  • 생성자가 다른 객체를 리턴하지 않기 때문에 이 새로 생성된 객체가 new에서 리턴된다. 이 값이 mine에 저장되어 mine은 새로 생성된 객체를 가리킨다.

이후 메모리에는 다음과 같은 상황이 된다.

mine은 MyFunction을 생성자로 해서 (new를 통해) 만들어진 객체이지만 mine의 프로토타입은 MyFunction이 아니라 MyFunction.prototype이라는 함수의 프로토타입 프로퍼티이다.

4. Prototype Chaining과 Shadowing

그러면 이 프로토타입은 어디에 쓰는 것인가? 어떤 객체의 프로퍼티(또는 메소드(프로퍼티가 함수인 경우))가 해당 객체에 없을 경우 JS는 해당 객체의 프로토타입 링크를 따라 ( [[prototype]] 값이 가리키는 값들 ) 거슬러 올라가며 해당 프로퍼티를 찾는다. 이를 프로토타입 체이닝(Prototype Chaining)이라고 한다. 다음의 예제를 보자.

var MyFunction = function() {
    this.a = 1;
}
var mine = new MyFunction();
MyFunction.b = 2;
MyFunction.prototype.b = 3;

>mine.b
3

mine에는 b라는 프로퍼티가 정의되어 있지 않다. 그래서 JS는 프로퍼티링크를 거슬러 가면서 b를 찾게 된다. 여기에서는 b의 값이 3인 것으로 보아 mine의 프로토타입은 MyFunction이 아니라 MyFunction.prototype임을 다시 확인할 수 있다.

어떤 프로퍼티의 값을 읽는 경우 ([[Get]] 오퍼레이션의 경우)에는 사실 큰 문제가 없을 수도 있다. 하지만 새로운 프로퍼티를 객체에 동적으로 할당하는 경우 ([[Put]] 오퍼레이션)에는 좀 다른 문제가 발생한다. 다음과 같은 예를 다시 보자.

var MyFunction = function() {
    this.a = 1;
}
var mine = new MyFunction();
MyFunction.prototype.b = 3;

mine.b = 4
>mine.b
4
>MyFunction.prototype.b
3  

앞에서 mine.b는 프로퍼티 링크를 타고 올라가 MyFunction.prototype.b 의 값을 읽었다. 하지만 mine에 직접 b라는 프로퍼티를 설정하면 b는 직접 mine객체의 프로퍼티로 생성된다. (MyFunction.prototype.b 와는 별개의 프로퍼티가 된다.) 이를 Shadowing이라고 한다.

Shadowing은 어떤 객체에 새로운 프로퍼티를 할당할 때 프로퍼티 링크 상의 상위 객체에 같은 이름의 프로퍼티가 있더라도 그 프로퍼티가 읽기 전용이 아니라면 해당 프로퍼티를 그냥 해당 하위 객체에 바로 생성한다. (상위 객체의 값을 바꾸는 것이 아니라)

상위의 프로퍼티가 읽기 전용이라면 (프로퍼티의 속성을 바꾸는 방법등은 여기서 다루지 않겠다.) 프로퍼티를 할당하려는 시도는 그냥 조용히 실패한다. (strict mode로 동작시에는 에러가 발생한다.) 한가지 특이한 경우는 상위 프로퍼티에 setter가 정의된 경우인데 (다른 언어들과 유사하게 JS의 프로퍼티들도 별도의 getter나 setter를 정의할 수 있다.) 이 경우에는 그 상위 setter가 실행되고 정작 하위의 객체에는 해당 프로퍼티가 생성되지 않는다.

5. Object.create()

생성자 함수를 이용해 new를 통해 객체를 생성하는 것은 위와 같이 매우 복잡한 과정이다. 만일 단순하게 객체를 생성하는 것만이 목적이라면 Object.create() 함수를 이용하면 된다.

var objSource = {
    a: 1,
    b: 2
};

var objNew = Object.create(objSource);

>objNew.a 
1
>objNew.b
2

Object.create 함수는 인자로 받은 객체를 프로토타입으로 하는 새로운 객체를 반환한다. 위의 예제에서 objNew는 Prototype Property가 없이 [[prototype]]이 objSource로 설정되는 객체이다.

6. Inspection

instanceof

JS에서 객체를 다루다보면 각 객체의 연관관계를 검사해야 하는 경우가 많이 생긴다. instanceof는 이 때 사용할 수 있는 연산자(메소드가 아님)이다. 다음의 예를 보자

mine instanceof MyFunction;     // true

instanceof 연산자는 좌항의 객체가 우항의 함수로 생성된 객체인지를 좌항 객체의 [[prototype]]을 거슬러가며 검사한다. 중요한 것은 우항이 항상 ‘함수’여야 한다는 것이다. 이것은 다시 말해 거슬러가면서 검사하는 것은 그 프로토타입 링크의 값이 우항 함수의 프로토타입 프로퍼티(위의 예에서는 MyFunction.prototype)인지를 확인한다는 것이다.

isPrototypeOf()

isPrototypeOf는 연산자가 아니라 Object의 메소드이다. 다시말해 해당 객체가 인자로 받는 객체로부터 생성된 (프로퍼티링크의 체인상에 존재하는) 객체인지를 검사한다. instanceof와 달리 검사하는 대상은 함수가 아니라 객체이다.

objSource.isPrototypeOf(objNew);    // true

getPrototypeOf()

Object의 메소드로 인자로 받은 객체의 프로토타입을 구하는 ( [[prototype]] 값을 알아내는) 공식적인 방법이다. 앞에서 이야기 했듯이 proto 프로퍼티를 쓰는 경우도 있지만 표준이 아니다. (Node.js에서는 지원한다.)

Object.getPrototypeOf(objNew) === objSource;    // true
Object.getPrototypeOf(mine) === MyFunction.prototype;    // true
Object.getPrototypeOf(mine) === MyFunction;    // false

여기까지가 JS의 프로토타입에 대한 중요한 내용들이다. 어떤 함수 객체의 프토토타입 프로퍼티 객체 (AFunction.prototype)는 이 함수를 생성자로 사용해 new로 만든 모든 객체에 프로토타입 링크의 체인으로 공유되기 때문에, 흔히 이 프로토타입 프로퍼티 객체에 프로퍼티나 메소드를 정의해 일종의 객체 상속과 같은 개념으로 활용한다. 하지만 엄밀히 말해 이는 상속이 아니라 일종의 위임(delegation)으로 봐야 한다. 이의 동작의 의미를 명확히 이해하기 위해서라도 프로토타입에 대한 정확한 이해가 중요하다.

다음 글에서는 역시 많은 사람들을 괴롭히는 ‘this’에 대해 이야기 해 보겠다.

 

Javascript Object

1. 들어가며

원래 이 블로그에서는 한국어 포스팅은 안 하려고 했는데 다른 것 보다는 이 블로그는 누가 읽어도 안 읽어도 뭐 크게 상관없다… 라는 스탠스가 기본이었기 때문이다. 하지만 왠지 이런 기술관련 글은 혹시 도움이 될 사람이 있을지도 모른다는 생각에 간만에 한국어 포스팅을 해 보기로 했다. 혹시 시간이 되면 영어나 일본어로 다시 써보게 될지도 모르겠지만.

최근 간만에 프로그래밍 관련 공부를 다시 하고 있는데 이전에 봤던 “You Don’t Know JS” 시리즈를 다시 읽고서 매우 감동을 받고 있다. Javascript를 보통 공부할 때 어느정도 익숙해지고 나면 읽게되는 유명한 책이 Douglas Crockford의 “JavaScript: The Good Parts” 이다. 이 책은 Javascript에 대한 이해를 높여주면서 이를 사용할 때 겪게되는 오류들을 미리 피할 수 있는 바람직한 코딩 가이드를 제공해 준다. 시간이 없는 사람들은 Crokford의 강연 비디오도 다양하게 올라와 있어 꼭 한번 보는 것이 좋다.

하지만 “You Don’t Know JS” 시리즈는 Javascript의 good parts만이 아니라 bad parts에 대해서도 충분한 이해가 필요하다는 생각에서 출발하고 있다. Javascript는 개인적으로 겪어본 프로그래밍 언어중에서 가장 특이하고 ‘현학적’인 언어라고 생각한다. 여전히 Javascript를 매우 ‘쉬운’ 언어라고 생각하는 사람들도 많은데 (사실 쉽게만 쓸 수 있기도 하다.) 이는 태생부터 이상하게 나온 Java + Script 라는 이름이 문제일지도 모르겠다. 혹시 해서 말하지만 Javascript는 Java와는 전혀 관련이 없으며 Script도 일반적으로 인지되는 ‘쉽다’와는 거리가 먼 언어이다. 물론 이는 그만큼 언어가 널리 쓰이게 되면서 보통은 신경쓰지 않아도 될 언어의 내부까지의 이해가 중요해졌기 때문이기도 하다.

보통 프로그래밍 언어를 공부하게 되면 1) 언어의 문법의 이해, 2) 특정 상황에 대한 해결방법 3) 언어 내부 구조의 이해 의 3단계를 거치게 된다고 생각한다. 사실 보통은 1), 2)만으로도 충분한 경우도 많다. 하지만 해당 언어를 정말로 전문가로서 활용하고 싶다면 3)의 과정은 매우 중요한데, Javascript는 이 3)이 매우 어려운편이고 (특히 C/C++ 계열의 언어에 익숙할수록 그러하다. 언어 자체는 마치 한국어와 영어처럼 그 근본이 다른 언어인데 문법적으로는 마치 비슷한 것 같은 모양을 띄고 있어서 더 그럴 수도 있겠다.) 더 잘 알수록 더 다른 사람이 이해하기 힘든 (현학적인) 코드를 만들어 낼 수 있다. 개인적으로는 이런 현학적인 코드를 가능한 만들지 않아야 한다고 생각하지만, Javascript에는 오랜 세월동안 만들어져온 일종의 패턴과 같은 많은 현학적 코드들이 존재한다. 그리고 그 코드들은 단지 자신의 지적 능력의 과시가 아닌, 꽤 현실적인 고민을 해결하기 위해 나온 경우가 많다. 그렇기 때문에 이를 이해하는 것 역시 매우 중요한 일이 된다.

그런 이유로 개인적으로 Javascript에 대한 글을 써보고 싶어졌다. 기본적으로는 내 자신의 공부를 위해서이다. (언제나 공부를 하는데 가장 좋은 방법 중 하나는 다른 사람에게 가르쳐 줄 수 있을만큼 파고들어보는 것이다.) 처음 이 글은 Javascript의 객체(Object) 개념에 대해 쓰고, 그 다음에는 많은 이들을 혼동시키는 ’prototype’에 대해 써 보고자 한다. 그리고 그 다음 글은 역시 많은 사람들을 충격과 공포로 인도하는;; ’this’에 대해 써 보려고 한다. (쓰다보니 너무 길어져 3개의 글로 나누려고 한다.) 책의 많은 부분은 앞에서 언급한 “You Don’t Know JS” 시리즈 중 “You Don’t Know JS: this & Object Prototypes” 편에서 영감을 얻고 있다. 하지만 단순한 번역은 아닌 개인적인 해석과 추가적인 이해에 도움되는 내용을 적고자 한다. 매우 좋은 책이기 때문에 관심있는 분들은 읽어봐도 좋을 것 같다. (참고로 이 글의 코드들은 기본적으로 브라우저 환경이 아닌 Node.js 환경을 가정하고 있다.)

2. Javacript의 모든 것은 객체이다?

흔히 Javascript의 모든 것은 객체이며 Javascript (만이) 진정한 객체지향언어라는 이야기를 한다. 하지만 엄격히 문법적으로 말하자면 사실이 아니다. Javascript에는 다음과 같이 6개의 기본 데이터 타입(primitive data type)이 있다. (You don’t Know JS (YDKJ) 기준으로)

  • string
  • number
  • boolean
  • null
  • undefined
  • object

좀 더 엄격하게 말하면 MDN reference에서는 5개의 primitive type (string, number, boolean, null, undefined)와 object로 구분하여 이야기하기도 한다. ES6부터는 symbol을 primitive type에 추가해 이야기한다. 다른 곳들과 달리 YDKJ에서는 소문자로 모든 기본 type을 쓰는데 (String이 아니라 string) 개인적으로는 이 편을 선호한다. 뒤에 나올 내장객체(Built-in Object)와의 혼동을 피하기 위함이다.

Note: Javascript에서는 모든 것은 객체이다…라고 이야기 되는 몇가지 ‘버그’들이 있는데 대표적인 것이 다음과 같은 것이다. null은 그 자신이 그냥 null인 primitive type이 맞다.

> typeof null
‘object’
// what the h… No, this is a bug.

’null’과 ‘undefined’: 이 두 개념도 꽤 만악의 근원…인데 기본적으로 공식 정의조차 매우 어긋나 있다. 언어 정의는 undefined는 어떤 변수가 선언되었지만 어떤 값을 할당받지 않은 상태를 말하고 null은 할당값이라고 설명하고 있다. 하지만 undefined와 null은 그 자체로 엄연한 primitive type이고 각각 ‘undefined’와 ‘null’이라는 값을 가진다. (null과 달리 typeof undefined는 ‘undefined’라고 잘 나온다.) 실제로 undefined는 다음과 같은 경우에 쓰인다.

  • 변수에 값이 할당되기 전의 기본 값
  • 함수가 호출될 때 caller로 부터 제공되지 않은 인자의 값
  • 접근한 객체의 프로퍼티가 ‘존재하지 않는’ 경우의 반환 값

이에 반해 null은 개인적인 감각으로는 언어 자체에 의해서 보다는 ‘프로그래머들에게서’ 사용되는 값이다. 원래는 선언은 되었지만 값이 없을 때 쓰이는 것으로 기획되었지만 사실 런타임에서는 이 용도로는 undefined가 더 일반적으로 쓰이기 때문이다. 이에 반해 프로그래머들은 위와 같은 용도로 null을 직접 많이 사용한다. 예를 들어 foo라는 변수를 선언하고 일단 ‘값이 없음’ 이라고 해 두려면 null을 넣어두는게 다른 언어를 사용하던 프로그래머들의 본성 아니겠는가? 이런 이유에서인지 언어 런타임 자체가 아니라 3자(?)가 제작한 프레임워크들의 함수에서는 어떤 객체를 요청했을 때 없는 경우 null이 리턴되는 경우가 많다. (브라우저에서 DOM 객체 접근시 getElementById 같은 함수에서 없으면 null이 넘어오는 게 대표적인 예이다.)

> var foo = null;
// yes, it is usual

3. Built-in Functions (내장 함수들)

위의 primitive type(굳이 기본타입이 아니라 primitive type이라고 하는 것은 한국어로 기본타입이라고 써 버리면 너무 일반적인 의미로 이해되기 때문이다. primitive type은 명확히 다른 내장 객체/함수들이나 다른 객체들과 구분해서 이해할 필요가 있다.)들은 이에 대응하는 내장(built-in) 객체를 가지고 있다. 아니, 매우 엄밀히 말하면 내장 객체가 아니라 그냥 ‘함수’이다. 뭐.. JS에서 함수도 객체 아닌가 하면 맞는 말이기도 하지만 함수는 조금 ‘특이한’ 객체이다. 이는 뒤에 다시 이야기하겠다. Primitive type들 중 undefined나 null을 제외하면 각각 대응하는 내장 함수들이 존재한다. 내장 함수들은 대표적으로 다음과 같은 것들이다. (구분하기 위해서 첫글자를 대문자로 쓴다.)

  • String
  • Number
  • Boolean
  • Object
  • Function
  • Array
  • Date
  • RegExp
  • Error

보다시피 바로 대응하는 것도 있고 Date나 RegExp처럼 primitive data type에는 없는 것들도 있다. 예를 들어 primitive type인 ‘string’과 내장 함수 String은 엄연히 다른 존재들이다.

var strPrimitive = "I am a string";
typeof strPrimitive; // 'string'
strPrimitive instanceof String; // false

var strObject = new String("I am a string");
typeof strObject; // 'object'
strObject instanceof String; // true

4. JS에서의 객체 생성

JS에서 객체를 생성하는 방법은 크게 3가지가 있다.

  • 1) 객체 literal로 생성하는 법
  • 2) 생성자 호출, 즉 함수에 new를 써서 생성하는 법
  • 3) Object.create() 를 써서 생성하는 법

3)은 많이 쓰이지 않지만 매우 좋은 방법이다. 왜 그런지는 추후 설명하고자 한다. 1)은 가장 선호되는 방법이다. JS는 간단한 선언 방법으로 객체를 선언할 수 있다.

var myObject = {
    a: 2,
    name: "I'm myObject"
};

> myObject
{ a: 2, name: 'I\'m myObject' }
> myObject.a
2
> myObject.name
'I\'m myObject'

Literal을 이용한 객체 선언은 간단한 객체의 선언이 필요할 때, JSON을 활용하여 객체를 선언할 때 등에서 매우 편리한 방법이다. 이에 비해 조금 복잡한 객체를 선언하거나 기존의 class 기반 객체지향 언어에 익숙한 사람들이 많이 사용할 수 있는 방법이 2)의 방법일 것이다.

var MyFunction = function() {
    this.a = 1;
this.name = "I am MyObject!";
}

var mine = new MyFunction();

> mine
MyFunction { a: 1, name: 'I am MyObject!' }

이 때의 MyFunction을 생성자/constructor라고 한다. 사실 이를 ‘생성자’라고 부르는 것도 많은 오해를 낳게 하는 악의 근원이다. 기존의 Java나 C++같은 클래스 기반 객체지향 언어를 사용하던 사람들이 볼 때 위의 코드는 매우 평이하게 보일 것이다. 비록 class라고 쓰지는 않았지만 JS에서 함수는 객체와 같다고도 했다. (정확히는 객체 중에는 함수객체라는것도 있는 것이지만) 그래서 함수를 new하면 mine이라는 인스턴스(instance)가 만들어졌다. 라고 생각한다. NO! 하지만 매우 유감이게도 이 말은 틀렸다.

기존의 class기반 객체지향 언어에서는 class는 일종의 청사진(blueprint)이다. 객체의 설계를 class에서 한다음 이를 실제 생성, 즉 인스턴스(instance)를 만드는 것이다. 기존 class기반 언어에서 위의 MyFunction과 mine의 관계는 다음 그림과 같이 이해된다.

하지만 JS에서는 이 class와 instance의 개념이 없다. 굳이 말하자면 모두 instance이지만 인스턴스라고 말하면 헷갈릴 수도 있어 JS에서는 그냥 이를 모두 object라고 한다. 다시말해 위의 MyFunction 부분은 다른 언어처럼 그냥 ‘선언(declaration)’이 아니다. 이 자체로 객체가 생성된다. 그래서 위의 MyFunction, mine은 각각 별도의 object로 존재한다. 그림으로 표현하면 다음과 같다.

5. new가 하는 일

위의 두번째 그림에서 한가지 재미있는 것은 화살표 방향이 첫번째 그림과는 반대라는 것이다. 이 화살표는 무엇인가?의 답을 알기 위해서는 정확하게 new가 어떤 일을 하는지 알아야 할 필요가 있다.

어떤 함수에 new를 사용하면 새로운 객체를 생성할 수 있다. 이 때 이 함수를 생성자(constructor)라고 한다. 여기서 중요한 개념은 생성자에 new를 사용해서 객체를 만드는게 아니라 “new에 사용되는 함수를 생성자라고 하는 것”이다. 다시 말해 모든 함수는 생성자가 될 수 있고 뭔가 따로 있는 것이 아니라는 것이다.

어떤 함수에 new를 사용하면 다음의 4단계의 동작이 발생한다.

  • 1) 새로운 객체가 생성된다.
  • 2) 새로 생성된 객체의 [[prototype]] 이 링크된다.
  • 3) 생성자함수의 this가 새로 생성된 객체로 (bind)되어 생성자가 호출된다.
  • 4) 새로 생성된 객체가 리턴된다 (new의 리턴값으로). 단, 한가지 예외가 있는데 해당 생성자가 다른 별도의 객체를 리턴하는 경우다. 이 경우는 새로 생성된 객체는 그냥 버려지고 생성자가 리턴하는 객체가 new의 리턴값이 된다.

위의 4단계를 잘 살펴보면 매우 중요한 개념을 알 수 있다. 생성자는 새로 생성된 객체와 강하게 연관된(기존 class/instance관계처럼) 그 무엇이 아니라 그냥 객체의 생성에서 호출되어 이를 도와주는 일종의 헬퍼와 같은 역할임을 알 수 있다. JS에서 함수, 즉 여기서의 생성자는 절대 다른 언어의 class와 같은 개념이 아니다. 다음 글에서는 2) 과정의 [[prototype]] 에 대해서 알아보겠다.

Zero to One, How Google Works and Lean Startup

연말과 연초에 걸쳐 2권의 책을 읽었다. 그 중 하나는 “How Google Works” (Eric Schmidt)이고 다른 하나는 “Zero to One” (Blake Masters and Peter Thiel) 이었다. How Google Works는 정확히 말하면 audible판으로 들었고 Zero to One은 번역본을 읽은 후 다시 오디오북으로 듣고 있다. 때문에 아무래도 How Google Works는 좀 더 이해도가 떨어질 수는 있겠지만 나름대로 두 책을 읽으면서 이전부터 startup에 일하면서 느꼈던 많은 점들을 다시 생각해 볼 수 있었다.

How Google Works의 각각의 내용은 어떻게 보면 대부분 이제는 너무 잘 알려진 이야기들이다. 이야기의 핵심은 결국 ’사람’으로 세상을 바꿀 수 있는 인재들 즉, “Smart Creatives”이다. 이런 Smart Creatives들을 어떻게 뽑고 이들에게 세상을 바꾸게 할 것인가가 Google이 일하는 핵심이다.

Peter Thiel은 Zero to One에서 시장경제의 완전자유경쟁시장은 환상이며 성공하는 기업이 되기 위해서는 ’독점’을 해야 한다고 한다. 심지어 독점이 가장 자본주의적이라고 하며 경쟁은 자본주의와 상극이라고 한다. 그러면서 Google을 독점으로 0에서 1을 이룬 대표적인 회사로 말하며 Google이 추구하는, 그리고 그들이 할 수 있고 하고 있는 수 많은 인재지향적인 정책들은 바로 이 독점이 준 혜택이라 말한다.

나 개인적으로도 그렇고 최근 Silicon Valley부터 한국까지 Startup의 바이블은 Lean Startup이라고 할 수 있을 것 같다. Eric Ries의 Lean Startup이 출간된 이래 이 책은 금융위기 이후 불확실한 시대에 Startup들의 지침서가 되어왔다. 데이터를 중시하고 가장 빨리 MVP(Minimum Valuable Product)를 만들어 A/B테스트를 통해 얻은 데이터로 끊임없이 iteration을 하는 Lean Startup 방법론은 agile 개발 방법론과 함께 절대적인 영향력을 행사하고 있다.

Zero to One은 이 Lean Startup을 기본부터 비판하고 있는 느낌이 든다. 이는 (비록 명시적으로 언급하지는 않지만) Lean Startup이 이야기하는 절대원칙들보다 정반대의 원칙이 오히려 옳다고 하기 때문이다. 하지만 개인적으로 여전히 Lean Startup은 불확실한 비지니스 환경에서 Startup들이 성공적인 비지니스를 성취하기 위한 가장 좋은 방법론이라고 생각한다. Zero to One이 문제로 삼는 것은 오히려 ’불확실한 비지니스 환경’과 ’성공적인 비지니스를 성취’하는 것을 목표로 삼는 것이다. 정말로 회사를 바꾸려는 Great한 회사가 되려면 확실한 독점시장에서 성공적인 따위가 아닌 완벽한 독점 (경쟁자들보다 10배 앞서 나아가는)을 이루라는 것이다.

Zero to One은 전략에 대한 이야기, Lean Startup은 이를 이루기 위한 전술에 대한 이야기이다. Paypal 조차 초창기의 Palm Pilot간의 송금서비스에서 E-mail을 통한 송금서비스로의 iteration, 그리고 EBay Powerseller를 대상으로 한 확장전략이라는 iteration이 가장 큰 역할을 하지 않았던가. 전술적 승리에 취해 전략 – 꿈꾸던 비전을 잊어버리거나 애초부터 비전자체가 없이 Startup을 시작하지 말라는 이야기인 것이다. 그래서 정말로 훌륭한 독점기업을 이루어 내었다면 그 다음부터의 수성은 Google 처럼 하면 될 것이다. 그 각각의 단계를 살피지 못하고 어느 하나에 매몰되거나 실망해서는 안된다. 가야 할 길은 참으로 멀다.

WWDC14 Keynote

이번 WWDC는 작년, 재작년과는 좀 다른 것들이 개인적으로 있는데, 가장 큰 것은 비용을 아끼기 위해 숙소를 Aribnb를 통해 처음으로 잡아 보았다. 싸게 잡더라도 Moscone근처의 호텔들은 이 시기면 200-350불 정도를 마구 나가는데 Airbnb에서 1박에 100불 아래로 Union Square에서 4블럭 정도 떨어진 곳에 집을 잡을 수 있었다. 방 자체는 매우 넓고 좋다. 주인 아주머니도 매우 친절한데.. 인터넷이 조금 느린것과 (호텔도 뭐 그렇긴 하니까) 화장실을 주인집이랑 share해야 하는 것이 조금 불편한 점이다. (그래도 가격을 생각하면…)
wpid-pastedgraphic4-2014-06-2-07-58.png

역시 잠을 일찍 깼기 때문에 4시 40분 부터 줄을 서기 시작했다.
언제나 느끼지만 혼자오면 이래저래 고생이 아니다. 앞뒤로 역시 혼자 온 애가 같이 서면 이야기라도 조금 하는데
오늘은 앞뒤로 모두 일행이어서 그냥 혼자서 줄을 섰다. 혼자 줄서면 화장실 가는게 문제기 때문에 일단 최대한 수분 섭취를 자제해야 한다… 왠지 작년보다 꽤 추웠던 느낌이었다.
wpid-pastedgraphic-2014-06-2-07-58.pngwpid-pastedgraphic1-2014-06-2-07-58.png

그래도 오늘은 좀 빨리 들여보내 주었다. 7:40분에 안으로 들어올 수 있었다. 줄을 서고 있으면 원래 뭔가 마케팅 하는 애들이 선물을 많이 주는데, 작년에 비해 공짜 선물들이 좀 줄어 들었다. 간단한 스낵 정도만 받을 수 있었다.

공식 선물은 언제나 처럼 자켓과 Pass. 올해는 특별히 25불 WWDC한정 iTunes카드를 주었다.
wpid-pastedgraphic3-2014-06-2-07-58.png
그래도 올해는 나름 과감하게 앞으로 가 봐서 역대 최고로 무대와 가까운 앞에서 2번째 블러의 2번째 줄 자리에 앉았다. 가장 앞 줄 블럭은 기자들이나 초대자들에게만 배정을 하니 일반 참가로서는 가장 앞에 가본 느낌이다. 내년부터는 같이 줄서는 사람이 없다면 굳이 새벽에 나오지는 않을 것 같다.

Keynote는 기대를 완전히 배신하여 새로운 Product는 하나도 나오지 않았지만 iOS8과 OSX10.10은 꽤 인상적이었다. 내용이야 많은 사람들이 이미 충분히 이야기 했다고 생각을 하기 때문에 개인적으로 인상적이었던 것은 이제 OSX와 iOS의 통합이 정말 완성단계로 갔기 때문에 기존에 나처럼 Mac을 메인으로 쓰는 사람은 이제 도저히 Android로 가기가 쉽지 않을 것 같다는 생각이다.

개발자의 입장에서는 뭐니뭐니해도 Swift가 가장 인상적이었다. 이런게 나오면 내일부터 모든 설명은 대부분 Swift를 통해서 할테니;;; 뜬금없는 새로운 언어가 튀어나왔지만 어차피 언어란 필요하면 배우는 것이고.. 일단 첫 느낌은 iOS의 개발은 원래부터 이랬어야 하지 않나..라는 긍정적 느낌이 강하다. 하지만 솔직히 경험상 과연 Swift가 언제부터 안정적으로 개발을 할 수 있는 환경이 될지. 정말로 9월에 iOS8나오면 그때에는 문제없이 쓸만한 물건이 될지는 약간 의문이다.

– Diko

WWDC 2014 줄서러 가기 전의 몇가지 예상..

올해도 왔으니…
이제 줄을 서로 출발하려고 하는 직전에 몇가지 예상을 해 본다.
사실 예상이라기 보다는 희망 사항이다.

– iPhone6는 나와야 한다.. 사실 해상도 바뀌는 것은 앱 개발에 매우
큰 이슈이기 때문에 x3 같은 것 한다면 분명히 iPhone6는 나와야 한다.
– iWatch도 나와야 한다. 다만 한번도 뭔가 정보가 흘러나온 적이 없다는게
문제인데 개인적으로는 그래도 HealthBook의 유용성을 위해서는 같이
나와주어야 하는 게 아닌가 한다.
– 덤으로 나올 수 있는 것은 4K Thunderbolt Display정도?

그래서 개인적으로는 우선 OSX 10.10 과 4K로 분위기를 잡고,
iOS로 가서 새로운 iOS8 설명하면서 이를 돌리기 위한 iPhone6,
그리고 iWatch로 가지 않을까..하는 희망을 말해본다 🙂

자 그럼 이제 줄서러 가자…

– Diko

WWDC 2013 결산

그래도 WWDC에 대해 블로그를 썼었는데.. 한동안 뒤를 마무리하지 못했었다. 가장 큰 이유는 원래 이런 이벤트는 끝나고 바로 바로 정리해야 하는데 WWDC는 원래 세션 내용 자체는 비공개여서 내용을 그 때 포스팅하지 못하기 때문이었다. 하지만 재미있는 것은 좀 지난 뒤지만 애플이 이번 WWDC 2013은 (거의) 모든 세션의 비디오를 유투브에 공개해 버렸다…라고 생각했지만 지금은 지워진 것을 보니 실수인가 한다;;; 비디오는 원래 Apple 개발자 (돈내는) 사이트에서는 공개하고 있다.

마무리 하는 차원에서 이번 WWDC를 뒤늦게 몇가지만 정리해 본다.

1. 그렇게 철저히 clearance하지 않더라.
이전 포스트에서는 반드시 나갔다가 다시 들어가야 한다..라고 했지만 올해는 (작년에도 그랬는지) 그렇게 철저히 하지 않았다. 그래서 한곳에서 계속 들으면 좋은 자리를 한번 킵하고 계속 보는 것이 가능했다. 그래도 Lunch session때는 철저히 모두 한번 내 보냈으며 일반 세션도 깐깐한 곳도 있긴 했으니 일종의 운영자의 맘..이지 않았던가 한다.

2. Tech Conference라기 보다는 종교 행사
wpid-pastedgraphic2-2013-07-21-17-04.png
일단 Apple Fanboy의 명성(?)은 모두 다 잘 알고 있을 것이라 생각하고… 올해 확실히 느꼈지만 이 행사는 확실히 종교 행사이다. 1600불이나 되는 등록비에 주는 것은 딱 저 자켓과 Pass 두개 뿐인것도 전통이고 각종 T셔츠나 모자 등의 상품은 모두 사야하지만 결국 없어서 못판다.

가장 인상적인 세션 중 하나였던 Join Adam Ritter와 Chad Evans가 나왔던 MLB at Bat의 런치 세션에서는 발표자 스스로 자신이 2010년 iPad 런칭시에 데모를 했던 감동과 Jobs가 자신의 어깨를 치며 “Good Job”이라고 해 주었다고 감동스러워하는 간증 스토리등이 인상적이었다;;

5000명의 개발자 참석자와 역시 천여명의 Apple 엔지니어들이 같이 어울리는 이 종교행사에 기본적으로 Apple에 대해 반감을 가진 사람을 거의 찾아볼 수 없는… 그런 행사이다.

3. 밥이 맛있다!
wpid-pastedgraphic3-2013-07-21-17-04.pngwpid-pastedgraphic4-2013-07-21-17-04.png
그래봐야 컨퍼런스 런치..라고 할 수 도 있지만 WWDC의 음식은 매우 훌륭하다. 아침마다 넘치는 Odwalla 쥬스는 잡느님이 오래전 직접 이것만 먹이라고 했다는 전설도 있고.. 아침의 빵과 베이글, 그리고 토스터까지 완비되어 있으며 점심은 매우 헬씨하지만 ‘촉촉한’ 샌드위치가 나온다. 아침은 커녕 점심도 안주었던.. 저번 GDC의 충격을 만회하기에 매우 좋았던 경험이었다. (물론 밥 자체는 re:Invent가 가장 낫긴 하다. 거긴 호텔 식사이니..) 한가지 팁? 이라면 공식 파티인 Bash에서는 절대 딤섬은 먹지 않는게 좋다. (매우 헬씨..한 느낌이 난다.)

4. 그래서 기술적으로 느낀점은?
iOS7은 뭐…이제 다들 어느정도 느낄지 모르지만 “매우 많이 바뀐다.” 어차피 전체를 다 따로 만드는 게임에서는 별 차이가 없을 것이지만 일반 native app을 만들던 사람들이라면 많은 변화를 각오해야 한다. 많은 사람들 사이에 새 UI에 대해 호불호가 갈리는 듯 하지만 개인적으로는 매우 좋아하고 있다.

역시 이제 매우 당연시 하는 것 같지만 Apple은 저가형 아이폰을 낼 것 같다. 사실 WWDC 이전에는 설마 라는 생각이 강했지만 전반적인 느낌은 iOS가 모든 모바일 도메인을 점령하는 것을 목표로 하고 있는 것 같다. 사실 게임쪽에서도 이번에 나온 Sprite Kit 같은 것 써서 게임 만들면 정말 좋을 것 같긴 하다. 다만 그러지 못하는 것은 안드로이드 지원 때문인데.. 결국 모든 방향성은 iOS만 개발하면 되게 해 주겠다. 였다고 생각한다. (물론 그렇게 되지는 않을 것 같다.)

그 외의 것들은.. 세션을 보기 바란다.

5. 맺으며
애플에 대한 애정이 있다면… 분명 WWDC는 최고의 Tech Conference다. 기술적인 것 뿐만 아니라 정신적인 안정까지 얻을 수 있으니 말이다; 내년에도 분명히 기회가 된다면 등에 ’14’ 라고 적힌 자켓을 얻기 위해 또 가보고 싶다.