구형 브라우저에서 es6 사용하기 (es6 to es5 webpack 빌드)


일반적인 웹 프로젝트에서는 es5를 쓰며 es6를 사용하기 위해서는 browser.js 혹은 babel.js를 load 해야 합니다.

그마저도 모든 es6 코드를 커버하지는 못하여 아래와 같이 es6 코드를 es5로 컴파일 해주는 webpack bundling 과정에 대해 설명 하겠습니다.


1. Node js 설치

  • 1-1. 윈도우 환경 기준으로 아래 사이트 접속 후 nodejs 를 다운 받습니다.



  • 1-2. 다운로드 후 설치 파일을 실행하여 NEXT 버튼 클릭으로 기본 설정 설치를 완료 합니다.


  • 1-3. 설치 완료 후 noedjs를 전역에서 실행 할 수 있도록 환경 설정을 진행 합니다.
    • 시스템속성 > 고급 > 환경변수 를 클릭하여 환경변수 설정을 진행 합니다.
    • 사용자 변수에 npm 위치 추가 ( C:\Users\사용자이름\AppData\Roaming\npm )

    • 시스템변수 > path > 새로만들기를 클릭하여 시스템 변수 nodejs를 추가합니다.

    • 윈도우 + R > node -v 로 nodejs 버전 확인이 가능하면 nodejs 설치가 끝났습니다.


2. Babel, webpack 빌드를 위한 설정

  • 2-1. 일반적은 프론트엔드 프로젝트의 경우 root 디렉토리, 스프링의 경우 src/main 위치에서 아래 순서대로 명령어를 수행 한다.

    • npm init -y : 프로젝트에서 npm 프로그램 시작을 의미하는 명령어 (실행 후 package.json 파일 자동 생성 완료)
    • npm install --save-dev webpack webpack-cli : 스크립트 간 의존성 관계를 하나의 파일로 bundling 해주는 webpack 설치
    • npm install --save-dev babel-loader : es6++ 이상의 문법에 대해 브러우저에 관계없이 동작되도록 컴파일 해주는 컴파일러
    • npm install --save-dev @babel/cli @babel/core @babel/preset-env : 위와 동일
    • npm install @babel/polyfill : babel 컴파일러만 설치 시 es6++ 문법에 대해 변환이 안되는 몇몇 가지 문제를 해결한 패키지


  • 2-2. 2-1 과 동일한 위치에 .babelrc 파일 생성
    • babel 환경 설정 

      {
        "presets": [
          [
            "@babel/preset-env",
            {
              "targets": {
                "browsers": [
                  "last 2 versions",
                  "not ie <= 9"
                ]
              }
            }
          ]
        ]
      }
  • 2-3. 2-1과 동일한 위치에 webpack.config.js 파일 생성
    • webpack 환경 설정 파일

      const path = require('path');
       
      module.exports = {
          entry: {
              index : ['@babel/polyfill''./webapp/js/bundle/index.js'// 빌드를 진행 하려는 파일 위치
              /*
              test1 : ['@babel/polyfill', './webapp/js/bundle/test1.js'], // 각각 파일로 빌드를 할 수 있짐만 비효율 적이므로 index.js 파일에 export 하여 한곳으로 빌드 추천
              test2: ['@babel/polyfill', './webapp/js/bundle/test2.js']
              */
          },
          output: { // 빌드 된 파일이 저장될 위치
              path: path.resolve(__dirname, './webapp/js/bundle'),
              filename: 'webpack.bundle.js'// filename : '[name].bundle.js',
              // library: "bundle", // 이름을 지정 할 경우 bundle.es6Code() 형태로 호출
              libraryTarget: "umd"// output.libraryTarget을 umd로 설정하면 모듈은 <script src=""> 로드 뿐만 아니라 모든 방식의 로더에서 사용할 수 있음
          },
          module: {
              rules: [
                  {
                      test: /\.js$/,
                      exclude: /node_modules/,
                      use: {
                          loader: 'babel-loader',
                          options: {
                              presets: ['@babel/preset-env']
                          }
                      }
                  }
              ]
          },
          devtool: 'source-map',
          mode: 'development'
      };
  • 2-4. package.json의 스크립트 수정
    • package.json 상단 부분에서 "script" 명령어를 아래와 같이 변경 한다.

    • 아래 설정의 의미는 npm run dev 명령어 수행 시 webpack 빌드를 진행할 것이고, -w의 경우 빌드 대상 파일을 watch 하며 변경이 일어날 경우 자동 재 빌드를 수행 함

      "scripts": {
        "dev""webpack -w --mode development --devtool inline-source-map",
        "build""webpack --mode production"
      },

3. TEST ES6 코드 작성 및 빌드 테스트

  • 3-1. TEST ES6 코드

    • src/main/webapp/js/bundle/classTest.js

      export class ClassTest {
          constructor(data) {
              this.data = data || "data";
          }
       
          call(){
              console.log("class test call : " this.data)
          }
      }
    • src/main/webapp/js/bundle/index.js

      export { ClassTest } from './classTest';
  • 3-2. npm 빌드 수행
    • npm run dev : 테스트 시
    • npm run build : 배포 시 (스크립트를 압축-minify  하여 코드라인 축소 및 난독화)
    • 빌드 시 2-3 output 위치에 webpack.bundle.js 파일 생성 됨


  • 3-3. jsp 혹은 html 파일에서 번들링된 파일을 로드 후 동작 테스트

    • src/main/webapp/WEB-INF/views/test.jsp

      <script src="${pageContext.request.contextPath}/js/bundle/webpack.bundle.js"></script>
      <script>
          let testCode = new ClassTest('code test');
          testCode.call();
      </script>

4. 빌드에 필요한 파일 목록

  • .babelrc
  • package.json
  • package-lock.json
  • webpack.config.js


JSONException 에러 관련


JSONArray, JSONException, JSONObject 등 json 처리 후 서버에 업로드 후 부팅 시 아래와 같은 에러가 발생하였음



 Caused by: java.lang.IllegalStateException: Failed to introspect Class [ 파일이름 ] from ClassLoader [ParallelWebappClassLoader

  context: ROOT

  delegate: false

----------> Parent Classloader:

java.net.URLClassLoader@37f8bb67

]

        at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:481) ~[spring-core-5.2.7.RELEASE.jar:5.2.7.RELEASE]

        at org.springframework.util.ReflectionUtils.doWithLocalMethods(ReflectionUtils.java:321) ~[spring-core-5.2.7.RELEASE.jar:5.2.7.RELEASE]

        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(AutowiredAnnotationBeanPostProcessor.java:267) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]

        ... 48 common frames omitted

Caused by: java.lang.NoClassDefFoundError: org/springframework/boot/configurationprocessor/json/JSONException

        at java.lang.Class.getDeclaredMethods0(Native Method) ~[na:1.8.0_201]

        at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) ~[na:1.8.0_201]

        at java.lang.Class.getDeclaredMethods(Class.java:1975) ~[na:1.8.0_201]

        at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:463) ~[spring-core-5.2.7.RELEASE.jar:5.2.7.RELEASE]

        ... 50 common frames omitted

Caused by: java.lang.ClassNotFoundException: org.springframework.boot.configurationprocessor.json.JSONException

        at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1365) ~[catalina.jar:9.0.37]

        at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1188) ~[catalina.jar:9.0.37]

        ... 54 common frames omitted



여기저기 검색해 보니 json 관련해서 잘못 dependency 되어 있는 문제였음


기존 : org.springframework.boot.configurationprocessor.json.JSONArray

변경 : org.json.JSONArray


maven


<dependency>

   <groupId>org.json</groupId>

   <artifactId>json</artifactId>

   <version>20200518</version>

</dependency>

 


gradle


implementation 'org.json:json:20200518'

 


디펜던시 참고 : https://javalibs.com/artifact/org.json/json





Xss custom filter (lucy 적용 안되어 임시방편 코드)


유지보수 프로젝트 수행 중 취약점 처리 요청이 들어와서 확인해보니 xss 필터 사용이 안되고 있었다.
lucy 필터가 쉽게 적용이 되어 lucy 필터를 적용 하려고 했으나 레거시 소스 + 특이사항 등.. 문제점이 있어서 정부에서 제공한 취약점 가이드에서 예외 처리 해야할 스크립트 동작 코드만 replace 처리 되도록 필터를 만들었다.

  • 아래 코드는 취약점 가이드에 표시되는 모든 스크립트 코드임 ( <, >, style 등.. 몇가지는 제외시킴 )
  • 해외에서 사용하는 Jsoup.clean() 을 사용하려고 코드를 넣었으나.. 혹시모를 레거시 코드 사이드이펙트를 우려하여 스크립트 코드만 처리함
public class XssEscape {

private static List<String> targetList = Arrays.asList(
"javascript", "script", "iframe", "document", "vbscript", "applet",
"embed", "object", "frame", "grameset", "layer", "bgsound",
"alert", "onblur", "onchange", "onclick", "ondblclick", "enerror",
"onfocus", "onload", "onmouse", "expression", "meta", "xml",
"onreset", "onmove", "onstop", "eval", "cookie", "onstart",
"onresize", "onmousewheel", "ondataavailable",
"onafterprint", "onafterupdate", "onmousedown",
"onbeforeactivate", "onbeforecopy", "ondatasetchanged",
"onbeforedeactivate", "onbeforeeditfocus", "onbeforepaste",
"onbeforeprint", "onbeforeunload", "onbeforeupdate",
"onpropertychange", "ondatasetcomplete", "oncellchange",
"onlayoutcomplete", "onmousemove", "oncontextmenu",
"oncontrolselect", "onreadystatechange", "onselectionchange",
"onrowsinserted", "onactivae", "oncopy", "oncut", "onbeforecut", "ondeactivate",
"ondrag", "ondragend", "ondragenter", "ondragleave", "ondragover", "ondragstart",
"ondrop", "onerror", "onerrorupdate", "onfilterchange", "onfinish", "onresizestart",
"onunload", "onselectstart", "onfocusin", "onfocusout", "onhelp", "onkeydown",
"onkeypress", "onkeyup", "onrowsdelete", "onlosecapture", "onbounce", "onmouseenter",
"onmouseleave", "onbefore", "onmouseout", "onmouseover", "onmouseup", "onresizeend",
"onabort", "onmoveend", "onmovestart", "onrowenter", "onsubmit"
);

public static String replaceValue(String str) {

String safeDoc = str;

if (StringUtils.isNotEmpty(str)) {
safeDoc = Jsoup.clean(str, Whitelist.relaxed().addTags("address"));
}

return safeDoc;
}

public static String replaceParam(String str) {

String returnStr = str;

if (StringUtils.isNotEmpty(str)) {

String str_low = str.toLowerCase();

for (String target : targetList) {
if (str_low.contains(target)) {
str = str.replaceAll(target, "");
returnStr = str;
}
}
}

return returnStr;
}

}


springboot 에서 jsp-config include 사용


spring의 web.xml에 설정되어 있는 전역 사용 jspf파일을 springboot java 코드로 변환하는 방법

기존코드

<jsp-config>
    <jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<include-prelude>/WEB-INF/views/common/layout/taglib/comTaglibs.jspf</include-prelude>
</jsp-property-group>
</jsp-config>


변경코드

import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.Context;
import org.apache.tomcat.util.descriptor.web.JspConfigDescriptorImpl;
import org.apache.tomcat.util.descriptor.web.JspPropertyGroup;
import org.apache.tomcat.util.descriptor.web.JspPropertyGroupDescriptorImpl;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.util.Collections;

@Component
@Slf4j
public class ServletInitailizer extends SpringBootServletInitializer {

@Bean
public ConfigurableServletWebServerFactory configurableServletWebServerFactory ( ) {
return new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
super.postProcessContext(context);
JspPropertyGroup jspPropertyGroup = new JspPropertyGroup();
jspPropertyGroup.addUrlPattern("*.jsp");
jspPropertyGroup.addUrlPattern("*.jspf");
jspPropertyGroup.setPageEncoding("UTF-8");
jspPropertyGroup.setScriptingInvalid("true");
jspPropertyGroup.addIncludePrelude("/WEB-INF/views/common/layout/taglib/comTaglibs.jspf");
jspPropertyGroup.setTrimWhitespace("true");
jspPropertyGroup.setDefaultContentType("text/html");
JspPropertyGroupDescriptorImpl jspPropertyGroupDescriptor = new JspPropertyGroupDescriptorImpl(jspPropertyGroup);
context.setJspConfigDescriptor(new JspConfigDescriptorImpl(Collections.singletonList(jspPropertyGroupDescriptor), Collections.emptyList()));
}
};
}
}


 

 

DB연결에러 ORA-03120: two-task conversion routine: integer overflow

 

sqldeveloper 사용 시 위와 같은 에러가 발생 하는 원인은 sqldeveloper 툴과 ojdbc 버전이 안맞아서 발생한다.

DBeaver 와 같은 다른 툴을 사용시와 각각 에러 보완 내용은 아래와 같다.

 

** 로컬에 ojdbc 버전별 다운로드 필요하며, 저의 경우에는 oracle 11g 연결 시 발생하였으므로 ojdbc6이 필요하였습니다.

ojdbc5.jar
다운로드
ojdbc6.jar
다운로드
ojdbc7.jar
다운로드
ojdbc8.jar
다운로드
ojdbc14.jar
다운로드

 

  • DBeaver
    1. 연결된 DB 우클릭 [Edit connection] 혹은 연결 세팅 화면에서 우측하단 [Edit Driver Settings] 을 선택
    2. Edit Driver 화면에서 [Add File] 선택 후 로컬에 다운받은 ojdbc 파일을 모두 추가한다
    3. 추가 후 재 연결 시도 시 정상적으로 연결이 수행 된다.
 
  • sqldeveloper
    1. sqldeveloper의 경우 현재 다운받을수 있는 18.x.x ~ 19.x.x 버전의 경우 jdk1.8 과 ojdbc8을 사용한다.
    2. oracle 홈페이지에서 oracle 11g 버전을 다운로드 한다. -> https://www.oracle.com/database/technologies/112010-win64soft.html
    3. jdk 1.6 (jdk-6u45) 파일을 다운 후 설치한다.
    4. 오라클 다운 후 설치 시 '데이터베이스 소프트웨어만 설치' 를 선택하면 DB 관련 툴만 설치가 가능하다.
    5. 설치 후 sqldeveloper PATH는 다음과 같음(대부분..) -> C:\ORACLE\virtual\product\11.2.0\dbhome_1\sqldeveloper
    6. sqldeveloper의 jdk.conf 위치로 이동한다.  -> C:\ORACLE\virtual\product\11.2.0\dbhome_2\sqldeveloper\ide\bin
    7. jdk.conf 파일 맨아래 다음과 같이 입력한다.  -> SetJavaHome C:\Program Files (x86)\Java\jdk1.6.0_45
    8. sqldeveloper을 다시 실행 후 oracle 11g 사용하는 원격지 연결 시 에러없이 정상 연결 된다.

 

스태틱 멤버



// 생성자
var Gadget = (function(){

// 스태틱 변수/프로퍼티
var counter = 0,
NewGadget;
// 이 부분이 생성자를 새롭게 구현한 부분
NewGadget = function(){
console.log(counter += 1);
};

// 특권 메서드
NewGadget.prototype.getLastId = function(){
return counter;
};

// 생성자를 덮어쓴다.
return NewGadget;
}());

var iphone = new Gadget();
iphone.getLastId(); // 1
var ipod = new Gadget();
ipod.getLastId(); // 2
var ipad = new Gadget();
ipad.getLastId(); // 3


전역 생성자


네임스페이스 패턴에서는 전역 객체가 하나다. 샌드박스 패턴의 유일한 전역은 생성자다.
// 샌드박스 사용법은 다음과 같다.
new Sandbox(function (box){
// 여기에 코드가 들어감
});

다음과 같이 new를 쓰지 않고도 가상의 모듈 'ajax'와 'event'를 사용하는 객체를 만들 수 있다.
Sandbox(['ajax', 'event'], function(box){
//console.log(box);
})

// 개별적인 인자로 전달 할 수 있다
Sandbox('ajax','dom', function(box){
//console.log(box);
})

샌드박스 객체의 인스턴스를 여러 개 만드는 예제
Sandbox(['dom', 'events'], function(box) {
// box 객체는 dom, events 모듈이 결합되어 있다.

Sandbox('ajax', function(box) {
// box 객체는 ajax 모듈만 결합되어 있다.
// 이 box 객체는 바깥 쪽 box 객체와 다르다.
});
});




모듈 추가하기


실제 생성자를 구현하기 전에 모듈을 어떻게 추가할 수 있는지 확인
// Sandbox 모듈 객체
Sandbox.modules = {};

// Sandbox 모듈 dom 정의
Sandbox.modules.dom = function(box) {
box.query = function(selector, context) {};
box.queryAll = function(selector, context) {};
box.css = function(el, prop, value) {};
}

// Sandbox 모듈 events 정의
Sandbox.modules.events = function(box) {
// 필요에 따라 Sandbox 프로토타입 객체에 접근 가능
// box.constructor.prototype.prop = 'value';
box.on = function(el, type, handler, capture) {};
box.off = function(el, type, handler, capture) {};
}

// Sandbox 모듈 ajax 정의
Sandbox.modules.ajax = function(box) {
box.makeRequest = function() {};
box.getResponse = function() {};
}




생성자 구현


function Sandbox() {
// arguments를 배열로 변경한다.
var args = Array.prototype.slice.call(arguments),
// 마지막 인자는 항상 콜백 함수이다.
callback = args.pop(),
// 모듈 이름은 배열 또는 문자열로 전달될 수 있다.
modules = (args[0] && typeof args[0] === 'string') ? args : args[0],
i;

// new를 강제화하는 패턴
if ( !(this instanceof Sandbox) ) {
return new Sandbox(modules, callback);
}

// 생성된 인스턴스 객체(this)에 속성을 추가 한다.
this.prop1 = 'property 1';
this.prop2 = 'property 2';

// this 객체에 모듈을 추가한다.
// 모듈이 없거나, '*' 와일드 카드라면 모든 모듈을 사용한다.
if (!modules || modules === '*' || modules[0] === '*') {
modules = [];
for ( var module in Sandbox.modules) {
if(Sandbox.modules.hasOwnProperty(module)){
modules.push(module);
}
}
}

// 필요한 모듈을 초기화 한다.
modules.forEach(function(module, index) {
Sandbox.modules[ module ](this);
});

// 콜백 함수를 실행한다.
callback(this);
}

// Sandbox 프로토타입 객체
Sandbox.prototype = {
name: 'Application',
version: '1.0.2',
getName: function(){
return this.name;
}
// ...
};


이 구현에서 핵심적인 사항은 다음과 같다.

  • this가 Sandbox 인스턴스인지 확인 후, 생성자 함수로 호출한다. (new를 강제화하는 패턴)
  • 생성자 내부에서 this에 속성을 추가한다. 생성자의 프로토타입 객체에도 속성을 추가할 수 있다.
  • 필요한 모듈은 배열 또는 개별 문자 유형의 인자로 전달할 수 있고, * 와일드카드를 사용하거나, 쓸 수 있는 모든 모듈을 사용하겠다는 의미로 인자를 생략할 수도 있다.
  • 필요한 모듈을 모두 파악한 다음에는 각 모듈을 초기화한다. 정리하면 각 모듈을 구현한 함수를 호출해서 객체를 생성한다.
  • 생성자의 마지막 인자는 콜백 함수이다. 이 콜백 함수는 맨 마지막에 호출되며, 새로 생성된 인스턴스가 인자로 전달된다. 이 콜백 함수가 실제로 사용자의 샌드박스이며 필요한 기능을 모두 갖춘 상태에서 box 객체를 전달받게 된다.


모듈 패턴


모듈 패턴은 늘어나는 코드를 구조화하고 정리하는데 도움이 되기 때문에 널리 쓰인다.
모듈 패턴은 다음 여러 패턴 여러개를 조합한 것이다.
  • 네임 스페이스 패턴
  • 즉시 실행 함수
  • 비공개 멤버와 특권 멤버
  • 의존 관계 선언


MYAPP.namespace('MYAPP.utilties.Array');


// 모듈 정의
MYAPP.utilities.array = (function(){
// 의존관계
var uobj = MYAPP.utilities.object,
ulan = MYAPP.utilities.lang,
// 비공개 프로퍼티
ayyay_string = "[object Array]",
ops = Object.prototype.toString;

// 비공개 메서드

// var 선언 종료

// 필요시 일회성 초기화 실행

// 공개 API
return {
inArray: function(needle, haystack){
for(var i = 0, max = haystack.langth; i < max; i += 1){
if(haystackp[i] === needle){
return true;
}
}
},

isArray: function(a){
return ops.call(a) === array_string;
}
// 더 필요한 메서드 추가
}
}())



모듈 노출 패턴


모든 메서드를 비공개 상태로 유지하고 최종적으로 공개 API를 갖출 대 공개할 메서드만 골라서 노출 하는 것이다.

MYAPP.namespace('MYAPP.utilities.Array');

// 모듈 정의
MYAPP.utilities.array = (function(){
// 비공개 프로퍼티
var ayyay_string = "[object Array]",
ops = Object.prototype.toString;

// 비공개 메서드
inArray = function(needle, haystack){
for(var i = 0, max = haystack.langth; i < max; i += 1){
if(haystackp[i] === needle){
return i;
}
}
return -1;
},
isArray = function(a){
return ops.call(a) === array_string;
};
// var 선언 종료

// 공개 API
return {
inArray: inArray,
indexOd: inArray
};
}());




생성자를 생성하는 모듈


앞선 예제는 MYAPP, utilities, array 라는 객체를 만들었다. 하지만 생성자 함수를 사용해 객체를 만드는게 더 편할때도 있다.

MYAPP.namespace('MYAPP.utilities.Array');

// 모듈 정의
MYAPP.utilities.Array = (function(){
// 의존관계
var uobj = MYAPP.utilities.object,
ulan = MYAPP.utilities.lang,

// 비공개 메서드
inArray = function(needle, haystack){
for(var i = 0, max = haystack.langth; i < max; i += 1){
if(haystackp[i] === needle){
return I;
}
}
return -1;
},
isArray = function(a){
return ops.call(a) === array_string;
},
Constr;
// var 선언 종료

// 공개 API 생성자
Constr = function(o){
this.elements = this.toArray(o);
};
// 공개 API 프로토타입
Constr.prototype = {
constructor: MYAPP.utilities.Array,
version: "2.0",
toArray: function(obj){
for(var i = 0, a = [], len = obj.length; i < len; i += 1){
ap[i] = obj[i];
}
return a;
}
}

// 생성자 함수를 반환한다
// 이 함수가 새로운 네임스페이스에 할당 될 것이다.
return Constr;
}());

// 이 생성자 함수는 다음과 같이 사용
var arr = new MYAPP.utilities.Array(obj);



모듈에 전역 변수 가져오기


변경 패턴으로는 모듈을 감싼 즉시 실행 함수에 인자를 전달하는 형태가 있다.

// 모듈 정의
MYAPP.utilities.module = (function(app, global){
// 전역 객체에 대한 참조와
// 전역 어플리케이션 네임스페이스 객채에 대한 참조가 지역 변수화 된다.
}(MYAPP, this));


비공개 프로퍼티와 메서드


자바 등 다른언어와는 달리 자바스크립트에는 private, protected, public 프로퍼티와 메서드를 나타내는 별도의 문법이 없다.

객체의 모든 멤버는 pulic, 즉 공개되어 있다.


var myobj = {
myprop: 1,
getProp: function(){
return this.myprop;
}
};
// 두개 모두 공개적으로 접근이 가능
console.log(myobj.myprop);
console.log(myobj.getProp());

// 생성자 함수를 사용해 객체를 생성할 때도 마찬가지로 모든 멤버가 공개된다.
function Gadget(){
this.name = 'iPod';
this.stretch = function(){
return 'iPod';
};
}
// 두개 모두 공개적으로 접근이 가능
var toy = new Gadget();
console.log(toy.name);
console.log(toy.stretch());



비공개 멤버


비공개 멤버에 대한 별도의 문법은 없지만 클로저를 사용해서 구현할 수 있다.
생성자 함수 안에서 클로저를 만들면 클로저 유효범위 안의 변수는 생성자 함수 외부에 노출되지 않지만 객체의 공개 메서드 안에서는 쓸 수 있다. 즉 생성자에서 객체를 반환할 때 객체의 메서드를 정의하면 이 메서드 안에서는 비공개 변수에 접근할 수 있는것이다.

function Gadget(){
// 비공개 멤버
var name = 'iPod';
// 공개된 함수
this.getName = function(){
return name;
};
}

var toy = new Gadget();

// name 은 비공개 이므로 undefied 출력
console.log(toy.name);

// 공개 메서드에서는 name에 접근할 수 있다.
console.log(toy.getName());



비공개 멤버의 허점


function Gadget(){
// 비공개 멤버
var specs = {
screen_width: 320,
screen_height: 480,
color: "white"
};

// 공개함수
this.getSpecs = function(){
return specs;
}
}

var toy = new Gadget();

// name 은 비공개 이므로 undefied 출력
console.log(toy.name);

// 공개 메서드에서는 name에 접근할 수 있다.
console.log(toy.getName());


getSpec() 메서드가 specs 객체에 대한 참조를 반환하는 문제가 있다.

var toy = new Gadget(),
specs = toy.getSpecs();
specs.color = "black";
specs.price = "free";

console.dir(toy.getSpecs());

/*
파이어폭스 로그 결과

color: "black"​
price: "free"​
screen_height: 480​
screen_width: 320​
<prototype>: Object { … }
*/



객체 리터럴과 비공개 멤버



// v1
var myobj; // 이 변수에 객체를 할당
(function(){
// 비공개 멤버
var name = "my, oh my";

// 공개될 부분을 구현
myobj = {
getName: function(){
return name;
}
}
}());

console.log(myobj.getName());

// v2
var myobj = (function(){
// 비공개 멤버
var name = "my, oh my";

// 공개될 부분을 구현
return {
getName: function(){
return name;
}
}
}());

console.log(myobj.getName());




프로토타입과 비공개 멤버


생성자를 사용하여 비공개 멤버를 만들 경우 생성자를 호출하여 새로운 객체를 만들 때마다 비공개 멤버가 매번 재생성된다는 단점이 있다.
이러한 중복을 없애고 메모리를 절약하려면 공통 프로퍼티와 메서드를 생성자의 prototype 프로퍼티에 추가해야 한다.
function Gadget(){
// 비공개 멤버
var name = 'iPod';
// 공개함수
this.getName = function(){
return name;
};
}

Gadget.prototype = (function(){
// 비공개 멤버
var browser = "Mobile Webkit";

// 공개된 프로토타입 멤버
return {
getBrowser : function(){
return browser;
}
}
}())

var toy = new Gadget();
console.log(toy.getName()); // 객체 인스턴스의 특권 메서드
console.log(toy.getBrowser()); // 프로토타입의 특권 메서드



비공개 함수를 공개 메서드로 노출 시키는 방법


노출 패턴은 비공개 메서드를 구현하면서 동시에 공개 메서드도 노출 하는것을 말한다.
var myarray;

(function(){
var astr = "[object Array]",
toString = Object.prototype.toString;

function isArray(a){
return toString.call(a) === astr;
}

function indexOf(haystack, needle){
var i = 0,
max = haystack.length;
for (; i < max; i += 1){
if(haystack[i] === needle){
return i;
}
}
return -1;
}

myarray = {
isArray: isArray,
indexOf: indexOf,
inArray: indexOf
};
}());

console.log(myarray.isArray([1,2])); // TRUE
var a = myarray.isArray({0: 1}); // FALSE
// console.log(a); // false
console.log(myarray.indexOf(["A","B","C"], "C")); // 2
console.log(myarray.inArray(["A","B","C"], "C")); // 2


@Slf4j 사용시 log cannot be resolved 에러 처리


전자정부 3.5에서 3.8로 변경 후 log cannot be resolved 에러가 사라지지않는 문제가 발생했다.

검색 결과 아래과 같이 처리함


1. 이클립스의 Maven Dependencies 에서 lombok-1.18.8.jar 파일을 찾는다.

2. lombok-1.18.8.jar 파일을 우클릭 -> run as -> java application -> 프로세스 진행

3. lombok jar 파일이 실행되며 install 창이 표시된다.

4. specify location -> 이클립스 위치의 eclipse.ini 를 선택 -> install/update 진행

5. install 이 정상적으로 실행 된다.

6. 이클립스로 돌아와 프로젝트를 clean -> restart 한다.

7. log 관련 에러가 사라진다.


+ Recent posts