code

jQuery / JavaScript 코드를 구성하는 가장 좋은 방법 (2013)

codestyles 2020. 8. 18. 07:44
반응형

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

If these paths are not exactly like this the below will not work and you'll have to modify the paths.

Download requirejs and put require.js in your www/js directory.

in your page.html, delete all script tags and insert a script tag like:

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

create www/js/main.js with content:

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

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

then put all the code you just fixed up in Steps 1-3 (whose only global variable should be App) in:

www/js/app.js

At the very top of that file, put:

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

At the bottom put:

})

Then load page.html in your browser. Your app should work!

Step 6) Create another file

Here is where your work pays off, you can do this over and over.

Pull out some code from www/js/app.js that references $ and App.

e.g.

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

Put it in www/js/foo.js

At the very top of that file, put:

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

At the bottom put:

})

Then change the last line of www/js/main.js to:

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

That's it! Do this every time you want to put code in its own file!


For your question and comments I'll assume you are not willing to port your code to a framework like Backbone, or use a loader library like Require. You just want a better way to orgainze the code that you already have, in the simplest way possible.

I understand it is annoying to scroll through 2000+ lines of code to find the section that you want to work on. The solution is to split your code in different files, one for each functionality. For example sidebar.js, canvas.js etc. Then you can join them together for production using Grunt, together with Usemin you can have something like this:

In your html:

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

In your Gruntfile:

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

If you want to use Yeoman it will give you a boilerplate code for all this.

Then for each file itself, you need to make sure you follow best practices and that all the code and variables are all in that file, and don't depend on other files. This doesn't mean you can't call functions of one file from other, the point is to have variables and functions encapsulated. Something similar to namespacing. I'll assume you don't want to port all your code to be Object Oriented, but if you don't mind refactoring a bit, I'd recommend to add something equivalent with what is called a Module pattern. It looks something like this:

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
  }
})();

Then you can load this bit of code like this:

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

This will allow you to have a much more maintainable code without having to rewrite your code too much.


Use javascript MVC Framework in order to organize the javascript code in a standard way.

Best JavaScript MVC frameworks available are:

Selecting a JavaScript MVC framework required so many factors to consider. Read the following comparison article that will help you to select best framework based on the factors important for your project: http://sporto.github.io/blog/2013/04/12/comparison-angular-backbone-can-ember/

You can also use RequireJS with the framework to support Asynchrounous js file & module loading.
Look the below to get started on JS Module loading:
http://www.sitepoint.com/understanding-requirejs-for-effective-javascript-module-loading/


Categorize your code. This method is helping me a lot and does work with any js framework:

(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();
    });
})();

In your preferred editor (the best is Komodo Edit) you may fold in by collapsing all entries and you will see only the titles:

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

I would suggest:

  1. publisher/subscriber pattern for event management.
  2. object orientation
  3. namespacing

In your case Jessica, divide the interface into pages or screens. Pages or screens can be objects and extended from some parent classes. Manage the interactions among pages with a PageManager class.


I suggest that you use something like Backbone. Backbone is a RESTFUL supported javascript library. Ik makes your code cleaner and more readable and is powerful when used together with requirejs.

http://backbonejs.org/

http://requirejs.org/

Backbone isn't a real library. It is meant to give structure to your javascript code. It is able to include other libraries like jquery, jquery-ui, google-maps etc. Backbone is in my opinion the closest javascript approach to Object Oriented and Model View Controller structures.

Also regarding your workflow.. If you build your applications in PHP use the Laravel library. It'll work flawlessly with Backbone when used with the RESTfull principle. Below the link to Laravel Framework and a tutorial about building RESTfull APIs:

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

http://laravel.com/

Below is a tutorial from nettuts. Nettuts has a lot of High Quality tutorials:

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


아마도 yeoman http://yeoman.io/ 와 같은 도구를 사용하여 전체 개발 워크 플로를 구현하기 시작할 때일 것 입니다. 이를 통해 모든 종속성, 빌드 프로세스 및 원하는 경우 자동화 된 테스트를 제어 할 수 있습니다. 시작해야 할 작업이 많지만 일단 구현되면 향후 변경이 훨씬 쉬워집니다.

참고 URL : https://stackoverflow.com/questions/16736483/best-way-to-organize-jquery-javascript-code-2013

반응형