-
[ 번역 ]javascript tip 2Technique/ETC 2016. 6. 6. 11:09반응형
위글의 2번 항목 번역입니다.
오브젝트
namespace 권장
namespace는 중급 규모 이상의 애플리케이션 작성할때에 필수 패턴입니다.
javascript 에서는 global scope 오염을 막는 대신에, 단일의 어플리케이션의 global object를 작성하는 것이 주류 입니다.
또, prototype chain을 사용하는 것으로, module container를 작성하는 것도 가능합니다.12345678910111213141516171819202122var MYAPP = {};MYAPP.name = "My First SPA";MYAPP.data = "2015/06/25";MYAPP.Update = function(){...};MYAPP.Delete = function(){...};// オブジェクトのコンテナMYAPP.modules = {};MYAPP.modules.name = "My First SPA's first module";MYAPP.modules.data = {1 : "test",2 : "test2",3 : "test3"};cs
베스트 플랜 : namespace
더불어 namespace를 작성할시엔 서드파티 플러그인의 적용이나, 역으로 플러그인으로서 공개하여 사용될 경우, 이 단일의 글로벌 오브젝트가 충돌하게 될 경우도 발생할 것입니다.
따라서 아래와같이 정의합니다.1234if (typeof MYAPP === "undefined"){var MYAPP = {};}cs 그리고 이것을 조금도 짧게 단축한 작성법도 있습니다.
12var MYAPP = MYAPP || {};var MYAPP.module = MYAPP.module || {};cs
베스트 플랜 : javascript pattern 에서 발췌한 namespacejavascript가 제공하고 있는 namespace의 method같은 건 따로 없기 때문에, 각각이 자신이 생각하는 최고의 방법으로 namespace를 정의하고, 앞서 작성한 사람들의 예가 javascript namespace 로 구글링한다면 많은 참고가 될 것입니다.
namespace() 메소드는 이상할치 만큼 시사하는것이 있기 때문에, 이 자리를 더불어 소개해 드리고 싶습니다. 작가인 Stoyan Stefanov 씨의 설명은 매우 알기 쉽기 때문에, 여기서 이해가 되지 않는다면 꼭 원서를 읽어보세요원서 : javascript pattern
우선 아래와 같은 namespace를 준비합니다.1234567var MYAPP = {modules: {moduleA: {},moduleB: {}}};cs
이것은 예를 들어 아래와같은 namespace() method로 정의가능하도록 합시다.12MYAPP.namespace('MYAPP.modules.moduleA');MYAPP.namespace('MYAPP.modules.moduleB');cs
또, 여기서 소개되고 있는 method는 아래와 같은 선언방법에도 대응하고 있습니다.123456789// 반환치를 로컬변수에 대입함var module2 = MYAPP.namespace('MYAPP.modules.module2');module2 === MYAPP.modules.module2; // true// 선두의 MYAPP을 생략MYAPP.namespace('modules.module51');// 긴 namespaceMYAPP.namespace('once.upon.a.time.there.was.this.long.nested.property');cs
그럼 실제로 코드를 볼까요?1234567891011121314151617181920var MYAPP = MYAPP || {};MYAPP.namespace = function(ns_string){var parts = ns_string.split('.'), // . で区切った配列parent = MYAPP, // グローバルオブジェクトのアプリ名i;// 선두의 글로벌을 제거if ( parts[0] === "MYAPP"){parts = parts.slice(1); // 先頭を削除}for ( i = 0; i < parts.length; i += 1){// property가 존재하지 않으면 작성함if ( typeof parent[parts[i]] === "undefined"){parent[parts[i]] = {}; // モジュールのオブジェクト生成}parent = parent[parts[i]];}};cs
public / private 를 의식한다.
우선, 다음의 코드를 봐 주세요
User() 함수는 user 오브젝트를 private 멤버로 가지고있으면서, id나 email의 변경이 쉽게 이루어 지지 않게 하고싶다.
또, private 멤버에 접근가능한 getUser() 메소드를 준비하였습니다.
(주) 이것은 안티 패턴 입니다. 따라하지 말아 주세요12345678910111213function User(){// private 멤버var userInfo = {userId: "user01",userEmail: "user01@gmail.com",userName: "David Brown"};// public 함수this.getUserInfo = function(){return userInfo;};}cs
이 설계에는 문제가 있습니다.아래의 호출 방법을 봐주세요
1234567var user = new User(),userInfo = user.getUserInfo();userInfo.email = "evil@gmail.com";userInfo.nickname = "Hello, world!";console.dir(user.getUserInfo());cs
이렇게 함으로써, 본래는 private 메소드인 userInfo의 내용이 오버라이드 되어 버립니다.
이러한 행위를 피하기위해서, private로 설정하고 싶은 오브젝트나, 배열에 대한 참조를 전달하지 않도록 할 수 밖에 없습니다\
예를들자면 이 경우, userId와 userName 만을 건내는 method를 작성한다면 좋을것 같습니다.1234567891011121314function User(){// private 멤버var userInfo = {userId: "user01",userEmail: "user01@gmail.com",userName: "David Brown"};// public 함수// 모든 은닉정보를 반환하지 않음( 필요한것만 반환 )this.getUserId = function(){return userInfo["userId"];}}cs
모듈패턴에 대한 지식
모듈패턴은
- namespance
- private 멤버와, public 멤버의 분리
- 무명함수
같은것을 조합하여 작성, 코드 작성을위한 패턴입니다. 모듈패턴을 적용함으로써, 기능별로 코드를 분리하는 것이 가능합니다. 더욱이, 각 기능별로 코드를 모아둠으로써 기능의 확장, 삭제, 리팩토링에 용이합니다.
또한 도입도 간단하기 때문에 상당히 많이 사용되고 있다 여겨집니다.
아래의 순으로 설명하겟습니다.
- 모듈 패턴 1 : namespace 준비
- 모듈 패턴 2 : 모듈의 정의
- 모듈 패턴 3 : 모듈을 사용
- 모듈 패턴 4 : 모듈의 공개
namespace 준비
우선은 namespace를 준비합니다.12345678var MYAPP = MYAPP || {util: {math: {}},data: {int: {}}};cs
모듈의 정의
다음은 모듈을 정의합니다.123MYAPP.util.math = (function(){// 여기에 처리를 작성합니다.}());cs
여기서, 개인적인 필요에 의해 무명함수를 활용가능합니다.
예를들면 여기서는 가감승제의 method를 제공한다고 합시다.123456789101112131415161718MYAPP.util.math = (function(){return {add: function(x, y){return x + y;},minus: function(x, y){// x 보다 y가 큰 경우 [x-y]를, 그렇지 않은경우 [y-x]를 반환합니다.return x > y ? x - y : y - x;},multiply: function(x, y){return x * y;},divide: function(x, y){// y가 0의 경우 「NaN(Not a number)」 를 반환합니다.return y !== 0 ? x / y : "NaN";}};}());cs
이렇듯 무명함수가 제공한 private scope를 사용함으로써, private의 property와 method를 필요에 따라 선언하는것이 가능합니다.
모듈을 사용함
마지막으로 이 무명함수가 돌려주는 오브젝트를 지정합니다.
위의 코드를 합쳐 봅시다.12345678910111213141516171819202122232425262728293031323334353637// (1)namespace 준비var MYAPP = MYAPP || {util: {math: {}},data: {int: {}}};// (2)모듈 정의MYAPP.util.math = (function(){return {add: function(x, y){return x + y;},minus: function(x, y){// x 보다 y가 큰경우 [x-y]를 그렇지 않은 경우엔 [y-x]를 반환return x > y ? x - y : y - x;},multiply: function(x, y){return x * y;},divide: function(x, y){// y가0인경우 「NaN(Not a number)」 를 반환합니다.return y !== 0 ? x / y : "NaN";}};}());// (3)모듈을 사용MYAPP.util.math.add(4,5);MYAPP.util.math.minus(4,5);MYAPP.util.math.multiply(4,5);MYAPP.util.math.divide(4,5);cs
모듈 공개
이것으로 지금까지 작성한 코드를 우선
- add, minus 등의 method를 private로 함
- 이어서, public API를 개시함 ( 반환할 method를 지정함 )12345678910111213141516171819202122232425262728293031323334353637383940414243// (1)名前空間の準備var MYAPP = MYAPP || {util: {math: {}},data: {int: {}}};// (2)モジュールの定義MYAPP.util.math = (function(){// 이것들 메소드를 private멤버로 정의add = function(x, y){return x + y;},minus = function(x, y){// x 보다 y가 큰경우 [x-y]를 그렇지 않은 경우 [y-x]를 반환합니다.return x > y ? x - y : y - x;},multiply = function(x, y){return x * y;},divide = function(x, y){// y가 0인경우 「NaN(Not a number)」 를 반환합니다.return y !== 0 ? x / y : "NaN";}// public APIreturn {add: add,minus: minus,multiply: multiply,divide: divide};}());// (3)모듈 사용MYAPP.util.math.add(4,5);MYAPP.util.math.minus(4,5);MYAPP.util.math.multiply(4,5);MYAPP.util.math.divide(4,5);cs
이로서 편리한 모듈 패턴의 예를 전부 소개해 드렸습니다.반응형'Technique > ETC' 카테고리의 다른 글
ubuntu 에 atom 설치 (0) 2016.08.24 [ 펌 ] 웹서버에 대한 기초지식 (0) 2016.07.13 [ 번역 ] javascript tip (0) 2016.06.03 [ 펌 ] 개발자, 바보처럼 보이는걸 두려워말자 (0) 2016.05.03 [ 펌 ] 개발자의 생명은 커뮤니케이션 능력 (0) 2016.04.25