CodeSnippet은 타입 체크나 배열 처리와 같이 자주 사용되는 코드의 모음으로, 외부 라이브러리와의 의존성을 줄이기 위해 만들었다. TOAST UI도 이런 이유로 CodeSnippet을 사용한다. CodeSnippet은 기능에 따라 여러개의 모듈로 분리되어 있어서, CodeSnippet 전체를 사용할 수도 있고, 필요한 모듈만 선택하여 사용할 수 있다. 하지만 TOAST UI 컴포넌트를 사용하고 있다면 반드시 CodeSnippet 전체를 사용하도록 한다.
이 문서는 CodeSnippet 사용이 익숙하지 않은 사용자들이 쉽게 따라 할 수 있게 하는데 목적이 있다. 그러므로 CodeSnippet이 제공하는 모든 기능을 설명하지는 않는다. CodeSnippet이 제공하는 다양한 기능과 관련 API는 아래 문서를 참고하기 바란다.
CondeSnippet은 npm, CDN, bower를 사용하여 설치할 수 있다.
npm으로 설치할 경우 아래와 같은 커맨드 라인 명령을 사용한다.
$ npm install --save tui-code-snippet # 최신 버전
$ npm install --save tui-code-snippet@<version> # 특정 버전
아래와 같이 CDN에 직접 접근해서 사용할 수 있다. npm 혹은 bower를 사용할 수 없다면 사전에 의존성 정보를 확인하고, 관련 코드들도 반드시 다운로드해야 한다.
<script src="https://uicdn.toast.com/tui.code-snippet/latest/tui-code-snippet.js"></script> <!-- 최신 버전 -->
<script src="https://uicdn.toast.com/tui.code-snippet/<version>/tui-code-snippet.js"></script> <!-- 특정 버전 -->
Bower로 소스코드를 가져올 경우 아래와 같이 커맨드 라인 명령을 사용한다.
$ bower install "tui-code-snippet" # 최신 버전
$ bower install "tui-code-snippet#<version>" # 특정 버전
CodeSnippet은 기본적으로 tui-code-snippet.js
와 tui-code-snippet.min.js
두가지 이름으로 배포된다. 프로젝트의 성격에 따라 파일명을 재정의할 수 있지만, 혼란을 줄이기위해 가급적 파일명은 변경하지 않고 그대로 사용하기를 권장한다.
const snippet = require('tui-code-snippet'); /* CommonJS */
import snippet from 'tui-code-snippet'; /* ES6 */
script 태그로 포함할 경우 tui.util
을 네임스페이스로 갖는다.
<!DOCTYPE html>
<html>
<head>
<title>HTML Page</title>
</head>
<body>
...
<script type="text/javascript" src="../js/lib/code-snippet.js"></script>
<script type="text/javascript" src="../js/app.js"></script>
</body>
</html>
import defineClass from 'tui-code-snippet/src/js/defineClass';
번들러를 사용할 때 필요한 모듈만 선택적으로 사용하면 의존성이 있는 파일만 번들에 포함되어 파일 사이즈를 줄일 수 있다.
CodeSnippet은 브라우저를 판별할 수 있는 snippet.browser
객체를 제공한다. browser.js가 로드되면 따로 실행하지 않아도, snippet.browser
객체의 속성으로 현재 브라우저의 정보가 자동으로 세팅되고 이 값들을 이용하여 브라우저별로 필요한 처리를 할 수 있다.
import snippet from 'tui-code-snippet';
const browser = snippet.browser;
if (browser.msie) {
alert("Internet Explorer");
} else if (browser.chrome) {
alert("Chrome");
} else if (browser.firefox) {
alert("FireFox");
} else if (browser.safari) {
alert("Safari");
} else if (browser.others) {
alert("Unknown");
}
브라우저 버전별로 다른 처리가 필요한 경우라면 version
속성을 사용할 수 있다.
const browser = snippet.browser;
if (browser.msie) {
if (browser.version < 8) {
alert("plz, upgrade your browser");
} else {
...
}
}
CodeSnippet은 데이터의 타입을 확인할 수 있는 메서드를 제공한다.
타입을 체크하는 메서드들은 모두 접두어 is
와 데이터 타입
의 조합으로 이름 지어졌다.
예를 들어 숫자형 데이터인지 판별하는 메서드는 "is"와 "Number"가 조합된 형태로 snippet.isNumber()
로 사용하면 된다.
const exam = 'fe';
snippet.isString(exam); // true
snippet.isNumber(exam); // false
snippet.isExisty(exam); // true
이 외에도isArray
, isObject
, isFunction
등 다양한 타입체크 메서드를 제공한다.
자세한 내용은 관련 [API 문서]를 참고하기 바란다.
CodeSnippet은 문자열을 HTML 엔티티로, HTML엔티티를 다시 문자열로 치환하는 기능을 제공한다. encodeHTMLEntity()
를 통해 예약된 문자를 HTML 엔티티로 치환할 수 있다. 또한, decodeHTMLEntity()
를 통해 HTML 엔티티를 예약된 문자로 치환 할 수 있다.
const htmlEntityString = '<div>FE devleopment Team <b>CodeSnippet</b></div>';
const result = snippet.encodeHTMLEntity(htmlEntityString);
// "<div>FE devleopment Team <b>CodeSnippet</b></div>"
const htmlEntityString = '<div>A 'quote' is <b>bold</b></div>';
const result = snippet.decodeHTMLEntity(htmlEntityString);
// "<div>A 'quote' is <b>bold</b></div>";
CustomEvents는 옵저버 패턴으로 구현되어 있으며 사용자가 이벤트를 정의하고 관리하는 API를 제공한다. 이어서 CustomEvents를 사용하는 두 가지 방법에 대해 설명한다.
믹스인을 통해 직접 해당하는 객체에 이벤트를 넣어 사용할 수 있다.
const Model = snippet.defineClass({
init: function() {
this.status = 'stop';
},
run: function() {
this.status = 'run';
},
getStatus: function() {
return this.status;
}
});
snippet.CustomEvents.mixin(Model);
const m = new Model(); // 인스턴스 생성
m.on('run', m.run.bind(m)); // 사용자 정의 이벤트 attach
m.fire('run'); // 사용자 정의 이벤트 발생 (이벤트 핸들러 실행)
m.getStatus(); // 'run'
다른 방법은 사용자 이벤트 객체를 대상 객체 내부 프로퍼티로 할당하여 이벤트를 처리하는 방법이다.
init
에서 이벤트 객체를 생성하여 내부 프로퍼티로 할당하면 해당 프로퍼티를 통해 이벤트를 발생시킬 수 있다.
const Model = snippet.defineClass({
init: function() {
this.status = 'stop';
},
run: function() {
this.status = 'run';
},
getStatus: function() {
return this.status;
}
});
const m = new Model();
m.event.on('run', m.run.bind(m), m); // event(내부 프로퍼티)를 통해 사용자 이벤트 attach
m.event.fire('run'); // event(내부 프로퍼티)를 통해 사용자 이벤트 발생 (이벤트 핸들러 실행)
m.getStatus(); // 'run'
추가로 이벤트 핸들러 처리 결과에 따라 다른 처리가 필요할 경우 fire()
대신 invoke()
로 이벤트를 발생시키고 결과 값을 반환 받을 수 있다. 사용 방법은 동일하다.
const m = new Model(); // 인스턴스 생성
m.event.on('run', handler, m); // 사용자 이벤트 attach
// invoke로 발생시킨 이벤트 결과에 따라 분기 처리
if (m.event.invoke('ready')) {
...
} else {
...
}
Enum
은 각기 다른 의미를 갖는 숫자의 나열을 가독성 있게 표현할 수 있다. 아래는 에러 타입을 Enum
을 이용하여 표현하는 예제이다.
// Enum 객체에 각 에러 코드를 순차적으로 넣어 ERRORCODE를 생성
const ERRORCODE = new snippet.Enum(['TYPE', 'VALUE', 'OPERATION', 'MEMORY', 'STATE']);
function printError(code) {
const {TYPE, VALUE, OPERATION, MEMORY, STATE} = ERRORCODE;
switch (code) {
case TYPE:
alert('타입 에러!');
break;
case VALUE:
alert('유효한 값이 아닙니다.');
break;
case OPERATION:
alert('유효하지 않은 호출입니다.');
break;
case MEMORY:
alert('메모리가 부족합니다.');
break;
case STATE:
alert('상태 에러!');
break;
default:
alert('알수없는 에러');
break;
}
}
function setObject(obj) {
// 인자의 데이터 타입이 바르지 않을 경우 타입 에러를 출력
if (!snippet.isObject(obj)) {
printError(ERRORCODE.TYPE); // 타입 에러를 발생
}
}
setObject('fe');
이 장에서는 ES5 이하 환경에서 사용할 수 있는 편의 기능을 설명한다. 브라우저가 같은 기능의 네이티브 API를 제공하는 경우 해당 API를 사용하기를 권장하며, 대체할 수 있는 API는 각 장의 상단에 명시하였다.
(ES5: Array.prototype.forEach)
forEach()
를 이용하면 배열 및 객체를 순회할 수 있다. 유사 배열의 경우, 순회하기 전에 배열로 변환이 필요하다.
// 일반 배열 순회
let sum = 0;
forEach([1, 2, 3], (value) => {
sum += value;
});
// 일반 객체 순회
let sum = 0,
obj = {
apple: 100,
orange: 200,
graph: 500,
...
};
forEach(obj, (value) => {
sum += value;
});
// 유사 배열 순회
function sum() {
//arguments(유사 배열)를 배열로 변환
const factors = Array.prototype.slice.call(arguments);
forEach(factors, (value, index) => {
...
});
}
(ES5: Array.prototype.filter)
filter()
를 이용하면 조건에 맞는 요소로만 추출된 부분 배열을 얻을 수 있다. 첫 번째 인자에 배열과 유사 배열을 모두 사용할 수 있으며, 두 번째 인자에 조건 비교를 수행할 함수를 넣는다.
const original = [100, 111, 23, 99, 101, 203, 1, 50];
snippet.filter(original, (value) => value > 100); // [111, 101, 203];
(ES5: Array.prototype.map)
map()
을 이용하면 연산을 통해 변경된 값으로 구성된 배열을 얻을 수 있다. filter
와 마찬가지로 첫 번째 인자에 배열과 유사 배열을 모두 사용할 수 있으며, 두 번째 인자에 조건 비교를 수행할 함수를 넣는다.
const placeCode = {
'100': 'INTERENCE',
'200': 'HELP DESK',
'300': 'RESTAURANT',
'400': 'LOCKER ROOM',
'500': 'CAFE'
};
snippet.map([100, 200, 300, 400, 500], (value) => placeCode[value]);
// ["INTERENCE", "HELP DESK", "RESTAURANT", "LOCKER ROOM", "CAFE"]
(ES5: Array.prototype.reduce)
reduce
를 이용하면 연산 결과를 누적할 수 있다. 첫 번째 인자는 명령을 수행할 배열, 두 번째 인자는 값을 변경하기 위한 함수를 넣는다.
let nArr, i;
for (nArr = [], i = 0; i < 100; i += 1) {
nArr.push(i);
}
const result = snippet.reduce(nArr, (stored, value) => {
if (value && value % 3 === 0) {
return stored + value;
}
return stored;
});
console.log(result); // 1683
(ES5: Array.from)
toArray
를 이용하면 유사배열을 배열로 변환할 수 있다.
const similarArray = {
0: 'one',
1: 'two',
2: 'three',
3: 'four',
length: 4
};
const result = snippet.toArray(similarArray); // ['one', 'two', 'three', 'four'];
(ES2015: Map 객체)
CodeSnippet은 해시 데이터를 설정하고 관리하는 해시맵을 제공한다. 필요한 CodeSnippet 파일을 로드한 후, 아래와 같이 해시맵을 생성한다.
const data = [
{
value: 'apple',
type: 'fruit'
},
{
value: 'mercedes',
type: 'car'
},
{
value: 'truck',
type: 'car'
},
{
value: 'lemonade',
type: 'beverage'
},
{
value: 'coke',
type: 'beverage'
}
];
let i = 0;
let len = data.length;
let cell, type;
let food = new snippet.HashMap(); // 해시맵 생성
for (; i < len; i += 1) {
cell = data[i];
type = food.get(cell.type);
// 이미 존재하면 추가, 아니면 새로 생성한다.
if (food.has(cell.type)) {
type.push(cell.value);
} else {
food.set(cell.type, [cell.value]);
}
}
// 결과 출력 함수
function showResult() {
i = 0;
len = food.length;
const keys = food.keys();
for(; i < len; i+= 1) {
console.log(keys[i], food.get(keys[i]));
}
}
console.log(food.length); // 3
console.log(showResult()); // fruit ["apple"]
// car ["mercedes", "truck"]
// beverage ["lemonade", "coke"]
each()
를 이용하면 해시맵을 순회할 수 있으며, remove()
를 이용하여 해시 데이터를 삭제할 수 있다.
food.each((value, key) => {
if (key === 'fruit') {
food.remove(key);
}
});
console.log(food.length); // 2
console.log(showResult()); // car ["mercedes", "truck"]
// beverage ["lemonade", "coke"]
(ES2015: Object.assign)
CodeSnippet은 extend
를 이용하여 객체를 확장하는 기능을 제공한다. extend
로 객체를 확장할 때에는 첫 번째 인자에 확장할 대상을 그리고 두 번째 인자는 확장할 값들을 넣어주면 된다.
const def = {
a: 10000,
b: 20000,
c: 30000
};
snippet.extend(def, {
d: 40000,
e: 50000,
f: 60000
}); // {a: 10000, b: 20000, c: 30000, d: 40000, e: 50000, f: 60000}
CustomEvent mixin
과, defineClass
에서 static
속성을 생성할 때 사용된다.
// CustomEvent mixin
CustomEvents.mixin = function(func) {
snippet.extend(func.prototype, CustomEvents.prototype);
};
// defineClass static
if (props.hasOwnProperty('static')) {
snippet.extend(obj, props.static);
delete props.static;
}
...
(ES2015: class 키워드)
snippet.defineClass()
를 이용하면 클래스 정의 및 상속을 구현할 수 있다.
// 클래스 정의하기
const Person = snippet.defineClass({
// 인스턴스 생성시 자동으로 실행되는 함수
init: function(name) {
this.name = 'Name: ' + name;
...
},
// 생성자 클래스 정적 멤버 정의
static: {
company: 'NHN Cloud',
getComany: function() {
...
}
...
},
// 생성자 프로토타입에 들어갈 멤버 정의
getName: function() {
...
}
...
});
스크립트 코드에서 snippet.defineClass()
에 클래스로 생성할 객체를 넘겨 클래스를 생성할 수 있다. 이때 init
은 인스턴스가 생성될 때 실행되는 생성자 함수로 초기화 시 수행될 코드를 정의하고, static
은 클래스의 정적 멤버를 정의한다. 그 외 메서드와 변수는 생성자 프로토타입에 들어간다.
// 인스턴스 생성하기
const hanjung = new Person('hanjung');
// 인스턴스 메서드 호출하기
hanjung.getName();
예제와 같이 new
키워드로 인스턴스를 생성할 수 있다.
(ES2015: extends 키워드)
상속은 클래스를 정의할때 이용했던 snippet.defineClass
에 추가 파라미터를 넘겨 구현할 수 있다.
// 부모 클래스 정의하기
const Parent = snippet.defineClass({
print: function() {
console.log(this.name);
}
});
우선 snippet.defineClass()
를 이용하여 상속을 위한 부모 클래스를 먼저 정의한다. 부모 클래스를 정의하는 방법은 일반 클래스를 정의하는 방법과 동일하며, 클래스 정의하기에서 이미 다루었다.
// 자식 클래스 정의
const Child = snippet.defineClass(Parent, {
init: function(name) {
this.name = name;
}
});
자식 클래스도 일반 클래스와 같은 방법으로 클래스를 정의하며, 파라미터만 다르다. 첫 번째 파라미터는 상속받을 대상이 되는 부모 클래스를 두 번째 파라미터에는 클래스로 생성할 객체를 넘긴다.
// 자식 인스턴스 생성
const child = new Child('fe');
// 인스턴스 메서드 호출
child.print(); // 'fe'
Child 클래스는 Parent 클래스를 상속받았기 때문에 자신에게는 없는 부모의 print()
를 사용할 수 있다.
지금까지 TOAST UI CodeSnippet에 대해 간단히 알아보았다. ES2015의 확산으로 과거에 비해 역할이 줄었지만, 여전히 CodeSnippet은 개발에 도움이 되는 많은 기능을 제공하고 있다. 이 가이드가 TOAST UI CodeSnippet을 보다 효율적으로 사용하는 데 도움이 되길 바란다.
이 문서는 NHN Cloud의 FE개발랩에서 작성하고 관리하는 공식 웹 프론트 개발 가이드이다. 가이드 적용 관련 문의나 문서의 오류, 개선 제안은 공식 문의 채널(dl_javascript@nhn.com)을 통해 할 수 있다.
Last Modified |
---|
2019. 03. 29 |