[javascript] jQuery / JavaScript 코드를 구성하는 가장 좋은 방법 (2013) [닫힌]

문제

이 답변은 이전에 답변되었지만 오래되었으며 최신이 아닙니다. 저는 단일 파일에 2000 줄 이상의 코드를 가지고 있으며, 우리 모두 알고 있듯이 이것은 특히 코드를 살펴 보거나 새로운 기능을 추가 할 때 나쁜 습관입니다. 현재와 ​​미래를 위해 내 코드를 더 잘 구성하고 싶습니다.

여러 리스너가 동일한 기능을 사용할 수있는 전역 범위에서 버튼, UI 요소, 드래그, 드롭, 액션 리스너 / 핸들러 및 기능이 많은 도구 (간단한 웹 사이트가 아님)를 구축하고 있음을 언급해야합니다.

예제 코드

$('#button1').on('click', function(e){
    // Determined action.
    update_html();
});

... // Around 75 more of this

function update_html(){ .... }

...

더 많은 예제 코드

결론

이 코드를 가장 잘 사용하고 반복하지 않고 새 기능을 추가하고 이전 기능을 업데이트 할 수 있도록이 코드를 구성해야합니다. 이 작업은 혼자서 할 것입니다. 어떤 선택자는 100 줄의 코드가 될 수 있습니다. 다른 것들은 1입니다. 나는 조금 보니 require.js반복적이며 실제로 필요한 것보다 더 많은 코드를 작성하고 있습니다. 이 기준에 맞는 가능한 모든 솔루션에 개방적이며 리소스 / 예제에 대한 링크는 항상 플러스입니다.

감사.



답변

도움이 될 수도 있고 아닐 수도있는 간단한 몇 가지를 살펴 보겠습니다. 일부는 명백 할 수도 있고 일부는 극도로 신비한 것일 수도 있습니다.

1 단계 : 코드 구분

코드를 여러 모듈 식 단위로 분리하는 것은 아주 좋은 첫 번째 단계입니다. “함께”작동하는 것을 모아서 작은 상자 안에 넣습니다. 지금은 형식에 대해 걱정하지 말고 인라인으로 유지하십시오. 구조는 나중 지점입니다.

따라서 다음과 같은 페이지가 있다고 가정합니다.

여기에 이미지 설명 입력

유지 관리의 용이성을 위해 (1000 줄을 검색 할 필요가 없음) 모든 헤더 관련 이벤트 처리기 / 바인더가 거기에 있도록 구획화하는 것이 좋습니다.

그런 다음 Grunt와 같은 도구를 사용하여 JS를 단일 유닛으로 다시 빌드 할 수 있습니다.

1a 단계 : 종속성 관리

RequireJS 또는 CommonJS와 같은 라이브러리를 사용하여 AMD 라는 것을 구현하십시오 . 비동기 모듈로드를 사용하면 코드가 의존하는 것을 명시 적으로 명시 할 수 있으며,이를 통해 라이브러리 호출을 코드로 오프로드 할 수 있습니다. 문자 그대로 “This needs jQuery”라고 말하면 AMD가이를로드하고 jQuery를 사용할 수있을 때 코드를 실행합니다 .

이것은 또한 숨겨진 보석을 가지고 있습니다. 라이브러리 로딩은 DOM이 준비되는 순간에 이루어집니다. 이것은 더 이상 페이지로드를 중단하지 않습니다!

2 단계 : 모듈화

와이어 프레임이 보이 시나요? 두 개의 광고 단위가 있습니다. 공유 이벤트 리스너가있을 가능성이 높습니다.

이 단계에서해야 할 일은 코드의 반복 지점을 식별하고이 모든 것을 모듈로 통합하는 것 입니다. 지금 모듈은 모든 것을 포함합니다. 우리는 진행하면서 물건을 나눌 것입니다.

이 단계의 전체 아이디어는 1 단계에서 모든 복사 파스타를 삭제하여 느슨하게 결합 된 장치로 교체하는 것입니다. 따라서 다음을 갖는 대신 :

ad_unit1.js

 $("#au1").click(function() { ... });

ad_unit2.js

 $("#au2").click(function() { ... });

난 ~을 가질 것이다:

ad_unit.js:

 var AdUnit = function(elem) {
     this.element = elem || new jQuery();
 }
 AdUnit.prototype.bindEvents = function() {
     ... Events go here
 }

page.js:

 var AUs = new AdUnit($("#au1,#au2"));
 AUs.bindEvents();

이를 통해 반복을 제거하는 것 외에도 이벤트마크 업 을 구분할 수 있습니다. 이것은 꽤 괜찮은 단계이며 나중에 이것을 더 확장 할 것입니다.

3 단계 : 프레임 워크 선택!

모듈화하고 반복을 더 줄이고 싶다면 MVC (Model-View-Controller) 접근 방식을 구현하는 멋진 프레임 워크가 많이 있습니다. 내가 가장 좋아하는 것은 Backbone / Spine이지만 Angular, Yii, … 목록이 계속됩니다.

모델 데이터를 나타냅니다.

보기 당신의 마크 업을 나타내며 모든 이벤트는 연관

컨트롤러는 비즈니스 로직을 대표하는 – 즉, 컨트롤러가 사용하는 부하에 어떤 전망과 어떤 모델 페이지를 알려줍니다.

이것은 중요한 학습 단계가 될 것이지만 그만한 가치가 있습니다. 스파게티보다 깨끗한 모듈 식 코드를 선호합니다.

당신이 할 수있는 다른 많은 일들이 있습니다. 그것들은 단지 지침과 아이디어 일뿐입니다.

코드 별 변경

다음은 코드에 대한 몇 가지 구체적인 개선 사항입니다.

 $('.new_layer').click(function(){

    dialog("Create new layer","Enter your layer name","_input", {

            'OK' : function(){

                    var reply = $('.dialog_input').val();

                    if( reply != null && reply != "" ){

                            var name = "ln_"+reply.split(' ').join('_');
                            var parent = "";

                            if(selected_folder != "" ){
                            parent = selected_folder+" .content";
                            }

                            $R.find(".layer").clone()
                            .addClass(name).html(reply)
                            .appendTo("#layer_groups "+parent);

                            $R.find(".layers_group").clone()
                            .addClass(name).appendTo('#canvas '+selected_folder);

            }

        }

    });
 });

이것은 다음과 같이 더 잘 작성됩니다.

$("body").on("click",".new_layer", function() {
    dialog("Create new layer", "Enter your layer name", "_input", {
         OK: function() {
             // There must be a way to get the input from here using this, if it is a standard library. If you wrote your own, make the value retrievable using something other than a class selector (horrible performance + scoping +multiple instance issues)

             // This is where the view comes into play. Instead of cloning, bind the rendering into a JS prototype, and instantiate it. It means that you only have to modify stuff in one place, you don't risk cloning events with it, and you can test your Layer stand-alone
             var newLayer = new Layer();
             newLayer
               .setName(name)
               .bindToGroup(parent);
          }
     });
});

코드 앞부분 :

window.Layer = function() {
    this.instance = $("<div>");
    // Markup generated here
};
window.Layer.prototype = {
   setName: function(newName) {
   },
   bindToGroup: function(parentNode) {
   }
}

갑자기 복사 붙여 넣기없이 코드의 어느 곳에서나 표준 레이어를 만들 수있는 방법이 생겼습니다. 당신은 이것을 5 개의 다른 장소에서하고 있습니다. 방금 5 개의 복사-붙여 넣기를 저장했습니다.

하나 더:

// 작업을위한 규칙 세트 래퍼

var PageElements = function(ruleSet) {
ruleSet = ruleSet || [];
this.rules = [];
for (var i = 0; i < ruleSet.length; i++) {
    if (ruleSet[i].target && ruleSet[i].action) {
        this.rules.push(ruleSet[i]);
    }
}
}
PageElements.prototype.run = function(elem) {
for (var i = 0; i < this.rules.length; i++) {
    this.rules[i].action.apply(elem.find(this.rules.target));
}
}

var GlobalRules = new PageElements([
{
    "target": ".draggable",
    "action": function() { this.draggable({
        cancel: "div#scrolling, .content",
        containment: "document"
        });
    }
},
{
    "target" :".resizable",
    "action": function() {
        this.resizable({
            handles: "all",
            zIndex: 0,
            containment: "document"
        });
    }
}

]);

GlobalRules.run($("body"));

// If you need to add elements later on, you can just call GlobalRules.run(yourNewElement);

이것은 표준이 아닌 이벤트 나 생성 이벤트가있는 경우 규칙을 등록하는 매우 강력한 방법입니다. 이것은 또한 pub / sub 알림 시스템과 결합 될 때 그리고 요소를 생성 할 때마다 발생하는 이벤트에 바인딩 될 때 매우 충격적입니다. Fire’n’forget 모듈 식 이벤트 바인딩!


답변

다음은 require.js를 사용하여 현재 코드베이스를 여러 파일로 분할하는 간단한 방법입니다. 코드를 두 개의 파일로 분할하는 방법을 보여 드리겠습니다. 그 후 더 많은 파일을 추가하는 것은 간단합니다.

1 단계) 코드 맨 위에 App 개체 (또는 MyGame와 같이 원하는 이름)를 만듭니다.

var App = {}

2 단계) 모든 최상위 변수와 함수를 App 개체에 속하도록 변환합니다.

대신에:

var selected_layer = "";

원하는 :

App.selected_layer = "";

대신에:

function getModified(){
...
}

원하는 :

App.getModified = function() {

}

이 시점에서 코드는 다음 단계를 완료 할 때까지 작동하지 않습니다 .

3 단계) 모든 전역 변수 및 함수 참조를 App을 통과하도록 변환합니다.

다음과 같이 변경하십시오.

selected_layer = "."+classes[1];

에:

App.selected_layer = "."+classes[1];

과:

getModified()

에:

App.GetModified()

4 단계) 이 단계에서 코드 테스트-모두 작동해야합니다. 무언가를 놓 쳤기 때문에 처음에는 몇 가지 오류가 발생할 수 있으므로 계속 진행하기 전에 수정하십시오.

5 단계) requirejs를 설정합니다. 코드가 다음과 같은 웹 서버에서 제공되는 웹 페이지가 있다고 가정합니다.

www/page.html

및 jquery

www/js/jquery.js

이러한 경로가 아닌 경우 정확히 이와 같지 아래가 작동하지 않으며 경로를 수정해야합니다.

requirejs를 다운로드 하고 require.js를www/js 디렉토리 .

에서 page.html모든 스크립트 태그를 삭제하고 다음과 같은 스크립트 태그를 삽입합니다.

<script data-main="js/main" src="js/require.js"></script>

www/js/main.js콘텐츠로 만들기 :

require.config({
 "shim": {
   'jquery': { exports: '$' }
 }
})

require(['jquery', 'app']);

그런 다음 1-3 단계에서 수정 한 모든 코드 (전역 변수 만 App이어야 함)를 다음 위치에 넣습니다.

www/js/app.js

해당 파일의 맨 위에 다음을 입력하십시오.

require(['jquery'], function($) {

하단에 넣어 :

})

그런 다음 브라우저에서 page.html을로드하십시오. 앱이 작동해야합니다!

6 단계) 다른 파일 만들기

여기에서 당신의 일이 보상을받는 곳입니다. 당신은 이것을 계속해서 할 수 있습니다.

에서 코드를 꺼내 www/js/app.js$ 및 App을 참조 .

예 :

$('a').click(function() { App.foo() }

넣어 www/js/foo.js

해당 파일의 맨 위에 다음을 입력하십시오.

require(['jquery', 'app'], function($, App) {

하단에 넣어 :

})

그런 다음 www / js / main.js의 마지막 줄을 다음과 같이 변경합니다.

require(['jquery', 'app', 'foo']);

그게 다야! 자체 파일에 코드를 넣고 싶을 때마다 이렇게하십시오!


답변

귀하의 질문과 의견에 대해서는 코드를 Backbone과 같은 프레임 워크로 이식하거나 Require와 같은 로더 라이브러리를 사용하지 않을 것이라고 가정합니다. 가능한 가장 간단한 방법으로 이미 가지고있는 코드를 얻을 수있는 더 나은 방법을 원할뿐입니다.

작업하려는 섹션을 찾기 위해 2000 개 이상의 코드 줄을 스크롤하는 것이 귀찮다는 것을 이해합니다. 해결책은 코드를 각 기능에 대해 하나씩 다른 파일로 분할하는 것입니다. 예를 들어 sidebar.js,canvas.js 등등. 그런 다음 Grunt를 사용하여 프로덕션을 위해 결합 할 수 있으며 Usemin과 함께 다음과 같은 것을 가질 수 있습니다.

HTML에서 :

<!-- build:js scripts/app.js -->
<script src="scripts/sidebar.js"></script>
<script src="scripts/canvas.js"></script>
<!-- endbuild -->

Gruntfile에서 :

useminPrepare: {
  html: 'app/index.html',
  options: {
    dest: 'dist'
  }
},
usemin: {
  html: ['dist/{,*/}*.html'],
  css: ['dist/styles/{,*/}*.css'],
  options: {
    dirs: ['dist']
  }
}

Yeoman을 사용하려면이 모든 것에 대한 상용구 코드를 제공합니다.

그런 다음 각 파일 자체에 대해 모범 사례를 따르고 모든 코드와 변수가 모두 해당 파일에 있고 다른 파일에 의존하지 않는지 확인해야합니다. 이것은 한 파일의 함수를 다른 파일에서 호출 할 수 없다는 것을 의미하는 것이 아니라 변수와 함수를 캡슐화하는 것입니다. 네임 스페이스와 비슷한 것. 모든 코드를 객체 지향으로 포팅하고 싶지는 않지만 리팩토링을 조금이라도 신경 쓰지 않는다면 모듈 패턴이라는 것과 동등한 것을 추가하는 것이 좋습니다. 다음과 같이 보입니다.

sidebar.js

var Sidebar = (function(){
// functions and vars here are private
var init = function(){
  $("#sidebar #sortable").sortable({
            forceHelperSize: true,
            forcePlaceholderSize: true,
            revert: true,
            revert: 150,
            placeholder: "highlight panel",
            axis: "y",
            tolerance: "pointer",
            cancel: ".content"
       }).disableSelection();
  }
  return {
   // here your can put your "public" functions
   init : init
  }
})();

그런 다음 다음과 같은 코드를로드 할 수 있습니다.

$(document).ready(function(){
   Sidebar.init();
   ...

이렇게하면 코드를 너무 많이 다시 작성하지 않고도 훨씬 더 유지 관리 할 수있는 코드를 가질 수 있습니다.


답변

자바 스크립트 코드를 표준 방식으로 구성하려면 자바 스크립트 MVC 프레임 워크를 사용하세요.

사용 가능한 최고의 JavaScript MVC 프레임 워크는 다음과 같습니다.

JavaScript MVC 프레임 워크를 선택하려면 많은 요소를 고려해야했습니다. 프로젝트에 중요한 요소를 기반으로 최상의 프레임 워크를 선택하는 데 도움이되는 다음 비교 기사를 읽으십시오.
http://sporto.github.io/blog/2013/04/12/comparison-angular-backbone-can-ember/

프레임 워크와 함께 RequireJS를 사용하여 비동기 js 파일 및 모듈로드를 지원할 수도 있습니다 .
JS 모듈 로딩을 시작하려면 아래를 참조하십시오 .
http://www.sitepoint.com/understanding-requirejs-for-effective-javascript-module-loading/


답변

코드를 분류하십시오. 이 방법은 나를 많이 돕고 모든 js 프레임 워크에서 작동합니다.

(function(){//HEADER: menu
    //your code for your header
})();
(function(){//HEADER: location bar
    //your code for your location
})();
(function(){//FOOTER
    //your code for your footer
})();
(function(){//PANEL: interactive links. e.g:
    var crr = null;
    $('::section.panel a').addEvent('click', function(E){
        if ( crr) {
            crr.hide();
        }
        crr = this.show();
    });
})();

선호하는 편집기 (최고는 Komodo Edit)에서 모든 항목을 접어 접을 수 있으며 제목 만 표시됩니다.

(function(){//HEADER: menu_____________________________________
(function(){//HEADER: location bar_____________________________
(function(){//FOOTER___________________________________________
(function(){//PANEL: interactive links. e.g:___________________


답변

내가 제안 할게:

  1. 이벤트 관리를위한 발행자 / 구독자 패턴.
  2. 개체 방향
  3. 네임 스페이스

귀하의 경우 Jessica, 인터페이스를 페이지 또는 화면으로 나눕니다. 페이지 또는 화면은 개체가 될 수 있으며 일부 상위 클래스에서 확장 될 수 있습니다. PageManager 클래스를 사용하여 페이지 간의 상호 작용을 관리합니다.


답변

Backbone과 같은 것을 사용하는 것이 좋습니다. 백본은 RESTFUL 지원 자바 스크립트 라이브러리입니다. Ik는 코드를 더 깨끗하고 읽기 쉽게 만들어 requirejs와 함께 사용할 때 강력합니다.

http://backbonejs.org/

http://requirejs.org/

백본은 실제 라이브러리가 아닙니다. 자바 스크립트 코드에 구조를 부여하기위한 것입니다. jquery, jquery-ui, google-maps 등과 같은 다른 라이브러리를 포함 할 수 있습니다. Backbone은 제 생각에 Object Oriented 및 Model View Controller 구조에 가장 가까운 자바 스크립트 접근 방식입니다.

또한 워크 플로우에 관해서도 .. PHP로 애플리케이션을 빌드하는 경우 Laravel 라이브러리를 사용하십시오. RESTfull 원칙과 함께 사용하면 Backbone에서 완벽하게 작동합니다. Laravel Framework 링크와 RESTfull API 빌드에 대한 자습서 아래 :

http://maxoffsky.com/code-blog/building-restful-api-in-laravel-start-here/

http://laravel.com/

아래는 nettuts의 튜토리얼입니다. Nettuts에는 많은 고품질 자습서가 있습니다.

http://net.tutsplus.com/tutorials/javascript-ajax/understanding-backbone-js-and-the-server/