Category Archives: 허접프로그래머

Javascript – 현대 모드 “use strict”

오랜 기간동안 Javascript는 호환성 문제 없이 진화하고 있었습니다. 새로운 기능은 언어에 추가되어갔지만 이전의 기능들은 변화가 없었습니다. 그것은 기존의 코드들의 동작을 깨뜨리지 않는다는 장점이 있었습니다. 하지만 Javascript 제작자가 저지른 실수나 불완전한 결정이 언어에 영원히 머무르게 되었다는 단점이 있습니다.

이러한 단점은 2009년에 ECMAScript 5 (ES5)가 등장할 때 까지 존재하였습니다. 여기에는 언어에 새로운 기능이 추가되고 기존 기능 중 일부가 수정되었습니다. 기존의 오래된 코드들이 동작하도록 하기 위해 이러한 수정 사항은 기본적으로 해제되어있습니다. 이것을 활성화 하기 위해서는 “use strict”를 사용하여 명시적으로 활성화 하여야 합니다.

“use strict”

이 지시자는 “use strict” 또는 ‘use strict’ 라는 문자열로 표현됩니다. 이것이 스크립트의 최상단에 위치하게 되면 모든 스크립트는 “현대적인” 방법으로 동작하게 됩니다. 예를 들면 다음과 같습니다.

"use strict";

// this code works the modern way
...

이러한 지시자는 스크립트의 시작 지점이 아니라 함수의 시작 지점에도 넣을 수 있습니다. 이렇게 할 경우 스크립트 전체가 아닌 해당 함수에만 엄격(Strict) 모드가 적용 됩니다. 하지만 일반적으로 사람들은 모든 스크립트에 적용되도록 사용합니다.

(주의) “use strict”는 최상단에 위치해야 합니다.

항상 “use strict”는 스크립트의 최상단에 위치하도록 해주십시오, 그 외의 경우에는 엄격 모드(Strict Mode)가 활성화 되지 않습니다. 다음은 엄격 모드가 활성화 되지 않는 예시입니다.

alert("some code");
// 아래에 있는 "use strict"는 무시됩니다. 최상단에 선언 되어야 합니다.

"use strict";

// 엄격 모드 (Strict Mode)는 활성화되지 않습니다.

(주의) use strict를 취소할 수 있는 방법은 없습니다.

“no use strict” 와 같은 혹은 비슷한 지시자는 존재하지 않습니다. 한번 엄격 모드가 활성화 되면 그것을 돌이킬 수는 없습니다.

항상 “use strict”를 사용합시다.

“use strict” 와 “default/sloppy” 모드의 차이점에 대해서 알아 볼 필요가 있습니다. 가령 다음과 같은 차이를 발견할 수 있습니다.

1) 일반적으로 어떠한 변수를 사용하기 위해서는 그것을 먼저 선언할 필요가 있습니다. 하지만 과거의 자바스크립트에서는 let 또는 var 없이도 값을 할당하는것만으로도 변수를 선언하는 것이 가능했습니다. 심지어 요즘의 자바스크립트에서도 “use strict” 없이는 여전히 가능합니다. 이러한 동작은 과거의 스크립트와의 호환성을 위한 모습입니다.

// "use strict" 를 사용하지 않은 예제입니다.

num = 5; // 변수 "num"은 존재하지 않음에도 생성됩니다.

alert(num); // 5

이것은 굉장히 나쁜 사용 예이며 엄격 모드(Strict Mode)에서는 오류를 발생하게 됩니다.

"use strict";

num = 5; // 에러: num is not defined

2) 또한 엄격 모드에서는 값의 할당에 대해 발생할 수 있는 오류들을 잡아주는 역할을 합니다.

"use strict";

// 쓰기 금지된 프로퍼티에 값 쓰기 시도
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // throws a TypeError

// Getter 밖에 없는 변수에 대한 값 할당 시도
var obj2 = { get x() { return 17; } };
obj2.x = 5; // throws a TypeError

// 확장 불가능한 객체에 대한 새로운 값 할당 시도
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // throws a TypeError

3) 엄격 모드에서는 삭제 불가능한 프로퍼티를 삭제하려고 시도할 경우 오류를 발생시킵니다. 이전에는 아무런 효과가 없던 코드입니다.

'use strict';
delete Object.prototype; // throws a TypeError

4) Gecko 34 버전 이전 브라우저들의 엄격 모드에서는 오브젝트의 모든 프로퍼티 이름은 고유해야 했습니다. 일반적인 코드에서 프로퍼티의 이름이 중복될 경우 마지막에서 할당한 값이 최종 값으로 결정되도록 하였습니다. 만약 마지막 값을 수정해야 하는데 실수로 그 이전 (중복된 이름의) 프로퍼티 값을 수정할 경우 정상적으로 적용이 안될 수 있으며 이는 엄격 모드에서 오류를 발생하게 변경되었습니다. (하지만 ECMAScript 2015에서 오류를 발생하지 않는것으로 원복되었습니다)

'use strict';
var o = { p: 1, p: 2 }; // !!! syntax error

5) 엄격 모드에서는 함수의 파라미터 이름이 고유해야 합니다. 보통의 코드들에서는 파라미터명이 중복될 경우 마지막 파라미터의 존재가 동일한 이름을 가진 이전 파라미터를 감추게 됩니다. 이 감춰진 파라미터는 arguments[i]로 접근할 수 있으므로 완벽하게 감추어진것도 아닙니다. 이는 의도적으로 감추고자 하더라도 완벽하게 수행될 수 없으므로 옳은 방법이 아닙니다. 그러므로 엄격 모드에서는 파라미터 명이 중복 될 경우 문법 오류가 발생합니다.

function sum(a, a, c) { // !!! syntax error
  'use strict';
  return a + a + c; // 만약 이 코드가 실행된다면 잘못된 동작을 하게 됨
}

6) ECMAScript 5의 엄격 모드에서는 8진 표현법의 사용을 금지합니다. 8진 표기법은 ECMAScript 5의 일부인것은 아니지만 모든 브라우저에서 앞에 0을 붙임으로써 표현이 가능합니다. (예: 0644 === 420 및 “\045” === “%”) ECMAScript 5에서의 8진 표기는 앞에 “0o”를 붙임으로써 지원 가능합니다.

var a = 0o10; // ES2015: Octal

초보 개발자들은 때때로 앞자리에 0을 붙이는 것이 특별한 의미가 없다고 생각하여 코드상의 정렬들 미관을 위해 사용합니다. 하지만! 값의 의미가 변경되게 됩니다. 앞자리에 0를 붙여 8진수로 만드는 것은 흔한 경우는 아니며 실수를 유발할 가능성이 더 크므로 엄격 모드에서는 오류를 발생시킵니다.

'use strict';
var sum = 015 + // !!! syntax error
          197 +
          142;

var sumWithOctal = 0o10 + 8;
console.log(sumWithOctal); // 16

7) ECMASCript 5의 엄격 모드에서는 원시 타입의 변수에 프로퍼티를 추가하는것을 허용하지 않습니다. 엄격 모드가 비활성화 상태일 경우 이러한 코드는 단순히 무시됩니다. 하지만 엄격 모드에서는 TypeError를 발생시킵니다.

(function() {
'use strict';

false.true = '';         // TypeError
(14).sailing = 'home';     // TypeError
'with'.you = 'far away'; // TypeError

})();

참고 :

  1. https://javascript.info/strict-mode
  2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode

Cocos2d-X 웹게임 개발하기 – Mac에서 개발환경 구축하기

웹기반 게임을 개발하기 위해서는 다양한 게임 엔진을 사용하는것을 고려해 볼 수 있습니다. 이 문서에서는 Cocos2d-X 를 이용하여 게임을 WEBGL 또는 CANVAS 환경에서 동작하는 게임을 만드는 과정을 설명하려 합니다. 먼저 개발 환경을 설정 할 것이며 Homebrew를 사용하는 맥 환경을 가정할 것입니다. 또한 개발 툴로는 IntelliJ를 사용할 것입니다.

1. JAVA 설치

우리는 Cocos2d-X를 사용하여 웹게임만을 개발할 생각이지만 JSB(Javascript Binding)이라는 기술을 사용하여 JS로 만들어진 게임 코드를 이용하여 iOS/Android 등과 같은 네이티브 게임을 빌드할 수 있습니다. 이러한 준비를 위하여 필요한 모든 것을 설치해 보도록 하겠습니다.

Homebrew를 사용하면 최신버전의 Java를 손쉽게 설치할 수 있습니다.

$ brew cask install java

위와 같은 명령을 사용하여 최신 버전의 Java를 설치할 수 있으며 설치 후 .bash_profile에 JAVA_HOME 환경 변수를 추가해주도록 합시다.

$ echo "export JAVA_HOME=`/usr/libexec/java_home`" >> ~/.bash_profile

2. Android SDK/NDK 설치

기존에 Android Studio를 활용중이라면 사용중인 SDK를 그대로 사용하셔도 무방합니다만 여기서는 Homebrew를 이용하여 SDK와 NDK를 설치하는 방법을 적어보겠습니다.

$ brew install android-sdk
$ brew install android-ndk

설치가 완료되면 다음의 명령을 사용하여 Android SDK를 업데이트할 수 있습니다.

$ android

이후에 뜨는 화면에서 자신이 빌드시에 사용하고자 하는 필요한 것들을 선택하여 설치를 진행하도록 합시다.

3. Python 및 Ant 설치

마찬가지로 Homebrew를 사용하여 Python과 Ant를 설치해보겠습니다.

$ brew install python
$ brew install ant

다음의 명령을 사용하여 Ant의 환경 변수를 추가해주도록 하겠습니다.

$ echo "export ANT_ROOT="/usr/local/opt/ant/bin"" >> ~/.bash_profile

4. Cocos2d-X 다운로드 및 설치

[Cocos2d-X 공식홈페이지]에 방문하면 최신버전의 Cocos2d-X 안정화 버전을 다운로드 받을 수 있습니다.

이 글을 작성할 시점에는 3.14.1 버전이 최신버전이네요. 다운로드 받도록 하겠습니다.

다운로드가 완료되었다면 압축을 풀고 적절히 원하는 위치에 옮겨놓도록 하겠습니다. 저는 홈디렉토리 밑에 cocos2d-x 디렉토리에 옮겨두었습니다. 이후에 셋업 명령을 실행합니다.

$ ./setup.py 

Setting up cocos2d-x...
->Check environment variable COCOS_CONSOLE_ROOT
  ->Search for environment variable COCOS_CONSOLE_ROOT...
    ->COCOS_CONSOLE_ROOT not found

  -> Add COCOS_CONSOLE_ROOT environment variable...
    ->Added COCOS_CONSOLE_ROOT=/Users/dennis/cocos2d-x/tools/cocos2d-console/bin

->Check environment variable COCOS_X_ROOT
  ->Search for environment variable COCOS_X_ROOT...
    ->COCOS_X_ROOT not found

  -> Add COCOS_X_ROOT environment variable...
    ->Added COCOS_X_ROOT=/Users/dennis

->Check environment variable COCOS_TEMPLATES_ROOT
  ->Search for environment variable COCOS_TEMPLATES_ROOT...
    ->COCOS_TEMPLATES_ROOT not found

  -> Add COCOS_TEMPLATES_ROOT environment variable...
    ->Added COCOS_TEMPLATES_ROOT=/Users/dennis/cocos2d-x/templates

->Configuration for Android platform only, you can also skip and manually edit "/Users/dennis/.bash_profile"

->Check environment variable NDK_ROOT
  ->Search for environment variable NDK_ROOT...
    ->NDK_ROOT not found

  ->Search for command ndk-build in system...
    ->Path /usr/local/Cellar/android-ndk/r13b was found

  -> Add NDK_ROOT environment variable...
    ->Added NDK_ROOT=/usr/local/Cellar/android-ndk/r13b

->Check environment variable ANDROID_SDK_ROOT
  ->Search for environment variable ANDROID_SDK_ROOT...
    ->ANDROID_SDK_ROOT not found

  ->Search for command android in system...
    ->Path /usr/local/Cellar/android-sdk/24.4.1_1 was found

  -> Add ANDROID_SDK_ROOT environment variable...
    ->Added ANDROID_SDK_ROOT=/usr/local/Cellar/android-sdk/24.4.1_1

->Check environment variable ANT_ROOT
  ->Search for environment variable ANT_ROOT...
    ->ANT_ROOT is found : /usr/local/opt/ant/bin


A backup file "/Users/dennis/.bash_profile.backup2" is created for "/Users/dennis/.bash_profile".

Please execute command: "source /Users/dennis/.bash_profile" to make added system variables take effect

셋업과정은 별고 없고 필요한 툴들을 찾아서 환경변수 혹은 PATH에 등록해주는것이 주요 목적입니다. 저의 경우에는 .bash_profile에 다음과 같은 환경변수가 등록되었습니다.

# Add environment variable COCOS_CONSOLE_ROOT for cocos2d-x
export COCOS_CONSOLE_ROOT=/Users/dennis/cocos2d-x/tools/cocos2d-console/bin
export PATH=$COCOS_CONSOLE_ROOT:$PATH

# Add environment variable COCOS_X_ROOT for cocos2d-x
export COCOS_X_ROOT=/Users/dennis
export PATH=$COCOS_X_ROOT:$PATH

# Add environment variable COCOS_TEMPLATES_ROOT for cocos2d-x
export COCOS_TEMPLATES_ROOT=/Users/dennis/cocos2d-x/templates
export PATH=$COCOS_TEMPLATES_ROOT:$PATH

# Add environment variable NDK_ROOT for cocos2d-x
export NDK_ROOT=/usr/local/Cellar/android-ndk/r13b
export PATH=$NDK_ROOT:$PATH

# Add environment variable ANDROID_SDK_ROOT for cocos2d-x
export ANDROID_SDK_ROOT=/usr/local/Cellar/android-sdk/24.4.1_1
export PATH=$ANDROID_SDK_ROOT:$PATH
export PATH=$ANDROID_SDK_ROOT/tools:$ANDROID_SDK_ROOT/platform-tools:$PATH

이후에 저기서 말해준대로 source 명령을 사용하여 추가된 환경변수를 적용 하도록 합시다.

$ source ~/.bash_profile

이제 cocos 명령이 정상 동작하는지 테스트를 해봅시다. 최초 실행시에 사용 정보를 자기네들 서버에 전송하는것을 허용할지 물어오는데 저는 No를 선택하였습니다. 어쨌든 문제없이 명령이 실행된다면 준비는 완료된 것입니다.

$ cocos 
Cocos collects data when the command-line tools are used for development. This data is examined in the aggregate only and is used to continually innovate and improve Cocos products. This data is anonymous and includes, but is not limited to, a unique hardware identifier, version number our software and information on which tools and/or services in Cocos products are being used and how they are being used. We take your privacy seriously and we do not share or sell any of this data. You can opt-out from sharing this data with us, but by sharing you help contribute to growth of Cocos.

Do you agree to sent the data? [Y]es, [N]o
N

/Users/dennis/cocos2d-x/tools/cocos2d-console/bin/cocos.py 2.2 - cocos console: A command line tool for Cocos2d-x.

Available commands:
	run              Compiles, deploy and run project on the target.
	gen-libs         Generate prebuilt libs of engine. The libs will be placed in 'prebuilt' folder of the engine root path.
	luacompile       Encrypt and/or compile lua files.
	deploy           Compile and deploy a project to a device/simulator.
	package          Manage package for cocos.
	compile          Compile projects to binary.
	gen-simulator    Generate Cocos Simulator.
	new              Creates a new project.
	jscompile        Compile and/or compress js files.
	gen-templates    Generate templates for Cocos Framework.

Available arguments:
	-h, --help			Show this help information.
	-v, --version			Show the version of this command tool.
	--ol ['en', 'zh', 'zh_tr']	Specify the language of output messages.

Example:
	cocos new --help
	cocos run --help

4. 프로젝트 생성

이제 터미널에서 cocos 명령을 사용하여 MyGame이라는 이름의 새로운 프로젝트를 생성해보도록 하겠습니다. 언어(-l)은 js로 패키지명(-p)는 kr.pe.theeye.mygame 으로 설정하였습니다.

$ cocos new MyGame -l js -p kr.pr.theeye.mygame
> Copy template into /Users/dennis/Documents/Project/MyGame
> Copying directory from cocos root directory...
> Copying files from template directory...
> Copying Cocos2d-x files...
> Rename project name from 'HelloJavascript' to 'MyGame'
> Replace the project name from 'HelloJavascript' to 'MyGame'
> Replace the project package name from 'org.cocos2dx.hellojavascript' to 'kr.pe.theeye.mygame'
> Replace the Mac bundle id from 'org.cocos2dx.hellojavascript' to 'kr.pe.theeye.mygame'
> Replace the iOS bundle id from 'org.cocos2dx.hellojavascript' to 'kr.pe.theeye.mygame'

이렇게 하면 프로젝트가 생성되고 프로젝트 디렉토리 내부로 들어가서 다음의 명령을 통해 바로 웹브라우저로 실행해볼 수 있습니다.

$ cocos run -p web
Building mode: debug
Deploying mode: debug
Starting application.
Try start server on 127.0.0.1:8000
Serving HTTP on 127.0.0.1, port 8000 ...

문제 없이 프로젝트가 생성되었다면 다음과 같은 화면을 볼 수 있습니다.

5. IntelliJ를 통해 프로젝트 관리하기

IntelliJ를 이용하여 프로젝트를 관리한다는건 사실 별다른게 있지는 않습니다. 그냥 IntelliJ로 프로젝트를 열면 알아서 자동완성을 포함한 프로젝트 구동에 필요한 모든것이 갖춰지게 됩니다.

Import Porject를 선택해도 되지만 그냥 Open으로 기존에 생성했던 MyGame 프로젝트를 열어보겠습니다.

MyGame을 찾아서 OK를 누르게 되면 프로젝트가 열리고 Indexing 과정을 거쳐 개발을 할 수 있는 환경이 자동으로 구축됩니다.

프로젝트 루트의 index.html을 마우스 우클릭하여 Run을 실행하게 되면 IntelliJ가 임의의 포트를 사용하여 프로젝트를 실행해 주게 됩니다.

참고 : http://blog.revivalx.com/2014/06/21/setting-up-your-cocos2d-js-environment/