[javascript] JavaScript에서 코드 구성과 관련하여 일반적으로 인정되는 모범 사례 [닫기]

jQuery와 같은 JavaScript 프레임 워크가 클라이언트 측 웹 애플리케이션을 더욱 풍부하고 기능적으로 만들면서 한 가지 문제점을 발견하기 시작했습니다.

이 세상을 어떻게 조직적으로 유지합니까?

  • 모든 핸들러를 한 곳에 배치하고 모든 이벤트에 대한 함수를 작성 하시겠습니까?
  • 모든 기능을 래핑하는 함수 / 클래스를 만드시겠습니까?
  • 미친 것처럼 쓰고 그것이 최선을 다하기를 바랍니다.
  • 포기하고 새로운 경력을 쌓으세요?

jQuery를 언급했지만 실제로는 일반적인 JavaScript 코드입니다. 줄 위의 줄이 쌓이기 시작하면 스크립트 파일을 관리하거나 찾고있는 것을 찾는 것이 더 어려워집니다. 내가 찾은 가장 큰 문제는 아마도 똑같은 일을 할 수있는 방법이 너무 많다는 것입니다.

.js 파일을 나머지 응용 프로그램처럼 멋지고 깔끔하게 유지하는 가장 좋은 방법에 대한 일반적인 권장 사항이 있습니까? 아니면 이것은 IDE의 문제입니까? 더 나은 옵션이 있습니까?


편집하다

이 질문은 파일 구성이 아니라 코드 구성에 관한 것입니다. 파일을 병합하거나 콘텐츠를 분할하는 몇 가지 좋은 예가 있습니다.

내 질문은 : 실제 코드를 구성하는 현재 일반적으로 허용되는 모범 사례 방법은 무엇입니까? 페이지 요소와 상호 작용하고 서로 충돌하지 않는 재사용 가능한 코드를 만드는 방법은 무엇입니까?

일부 사람들은 네임 스페이스 를 나열 했으며 이는 좋은 생각입니다. 페이지의 요소를보다 구체적으로 다루고 코드를 정리하고 깔끔하게 유지하는 다른 방법은 무엇입니까?



답변

자바 스크립트에 네임 스페이스가 내장되어 있으면 훨씬 좋을 것입니다. 그러나 Dustin Diaz와 같은 것을 조직 하면 여기 에 많은 도움이됩니다.

var DED = (function() {

    var private_var;

    function private_method()
    {
        // do stuff here
    }

    return {
        method_1 : function()
            {
                // do stuff here
            },
        method_2 : function()
            {
                // do stuff here
            }
    };
})();

다른 “네임 스페이스”와 때로는 개별 클래스를 별도의 파일에 넣었습니다. 일반적으로 하나의 파일로 시작하고 클래스 또는 네임 스페이스가 그것을 보증 할만 큼 커지면 자체 파일로 분리합니다. 제작을 위해 모든 파일을 결합하는 도구를 사용하는 것도 훌륭한 아이디어입니다.


답변

HTML에 자바 스크립트를 포함시키지 마십시오. 모든 코드는 클래스로 캡슐화되며 각 클래스는 자체 파일에 있습니다. 개발을 위해 각 js 파일을 포함하는 별도의 <script> 태그가 있지만 HTTP 요청의 오버 헤드를 줄이기 위해 프로덕션을 위해 하나의 큰 패키지로 병합됩니다.

일반적으로 각 응용 프로그램마다 하나의 ‘main’js 파일이 있습니다. 따라서 “survey”응용 프로그램을 작성하는 경우 “survey.js”라는 js 파일이 있습니다. 여기에는 jQuery 코드의 진입 점이 포함됩니다. 인스턴스화 중에 jQuery 참조를 작성한 다음이를 매개 변수로 오브젝트에 전달합니다. 이것은 자바 스크립트 클래스가 ‘순수’하며 CSS ID 또는 클래스 이름에 대한 참조를 포함하지 않음을 의미합니다.

// file: survey.js
$(document).ready(function() {
  var jS = $('#surveycontainer');
  var jB = $('#dimscreencontainer');
  var d = new DimScreen({container: jB});
  var s = new Survey({container: jS, DimScreen: d});
  s.show();
});

또한 명명 규칙이 가독성에 중요하다는 것을 알았습니다. 예를 들어 : 모든 jQuery 인스턴스 앞에 ‘j’를 추가합니다.

위 예제에는 DimScreen이라는 클래스가 있습니다. (이것은 화면을 어둡게하고 경고 상자를 팝업한다고 가정합니다.) 화면을 덮기 위해 확대하고 경고 상자를 추가 할 수있는 div 요소가 필요하므로 jQuery 객체를 전달합니다. jQuery는 플러그인 개념을 가지고 있지만 실제 거꾸로하지 않고 제한적인 것처럼 보입니다 (예 : 인스턴스가 영구적이지 않고 액세스 할 수 없음). DimScreen 클래스는 jQuery를 사용하는 표준 자바 스크립트 클래스입니다.

// file: dimscreen.js
function DimScreen(opts) { 
   this.jB = opts.container;
   // ...
}; // need the semi-colon for minimizing!


DimScreen.prototype.draw = function(msg) {
  var me = this;
  me.jB.addClass('fullscreen').append('<div>'+msg+'</div>');
  //...
};

이 접근법을 사용하여 상당히 복잡한 응용 프로그램을 만들었습니다.


답변

개발을 위해 스크립트를 별도의 파일로 나눈 다음 “릴리스”버전을 만들어서 모두 함께 크래킹하고 YUI 압축기 또는 이와 유사한 것을 실행할 수 있습니다.


답변

이전 게시물에서 영감을 받아 WysiHat (changelog에서 언급 한 RTE)과 함께 배포 된 Rakefile공급 업체 디렉토리 의 사본을 만들고 JSLint를 사용한 코드 검사 및 YUI Compressor로 축소 를 포함하도록 약간 수정했습니다 .

아이디어는 WysiHat의 Sprockets 를 사용 하여 여러 JavaScript를 하나의 파일로 병합하고 병합 된 파일의 구문을 JSLint로 확인한 후 배포 전에 YUI Compressor로 최소화하는 것입니다.

전제 조건

  • 자바 런타임
  • 루비와 갈퀴 보석
  • JAR을 클래스 경로 에 넣는 방법을 알아야합니다

이제 해

  1. Rhino를 다운로드 하고 JAR ( “js.jar”)을 클래스 경로에 넣으십시오.
  2. YUI Compressor를 다운로드 하고 JAR (build / yuicompressor-xyz.jar)을 클래스 경로에 넣으십시오.
  3. WysiHat을 다운로드 하고 “공급 업체”디렉토리를 JavaScript 프로젝트의 루트에 복사하십시오.
  4. Rhino 용 JSLint를 다운로드 하여 “공급 업체”디렉토리에 넣습니다.

이제 JavaScript 프로젝트의 루트 디렉토리에 “Rakefile”이라는 파일을 작성하고 다음 컨텐츠를 추가하십시오.

require 'rake'

ROOT            = File.expand_path(File.dirname(__FILE__))
OUTPUT_MERGED   = "final.js"
OUTPUT_MINIFIED = "final.min.js"

task :default => :check

desc "Merges the JavaScript sources."
task :merge do
  require File.join(ROOT, "vendor", "sprockets")

  environment  = Sprockets::Environment.new(".")
  preprocessor = Sprockets::Preprocessor.new(environment)

  %w(main.js).each do |filename|
    pathname = environment.find(filename)
    preprocessor.require(pathname.source_file)
  end

  output = preprocessor.output_file
  File.open(File.join(ROOT, OUTPUT_MERGED), 'w') { |f| f.write(output) }
end

desc "Check the JavaScript source with JSLint."
task :check => [:merge] do
  jslint_path = File.join(ROOT, "vendor", "jslint.js")

  sh 'java', 'org.mozilla.javascript.tools.shell.Main',
    jslint_path, OUTPUT_MERGED
end

desc "Minifies the JavaScript source."
task :minify => [:merge] do
  sh 'java', 'com.yahoo.platform.yui.compressor.Bootstrap', '-v',
    OUTPUT_MERGED, '-o', OUTPUT_MINIFIED
end

모든 것을 올바르게 수행했다면 콘솔에서 다음 명령을 사용할 수 있어야합니다.

  • rake merge -다른 JavaScript 파일을 하나로 병합
  • rake check-코드 구문을 확인하려면 (이것이 기본 작업이므로 간단히 입력 할 수 있습니다 rake)
  • rake minify -JS 코드의 축소 버전을 준비

소스 병합

Sprockets를 사용하면 JavaScript 전 처리기에서 require다른 JavaScript 파일을 포함 (또는 ) 할 수 있습니다. 다음 구문을 사용하여 초기 파일 ( “main.js”라는 다른 스크립트를 포함하지만 Rakefile에서 변경할 수 있음) :

(function() {
//= require "subdir/jsfile.js"
//= require "anotherfile.js"

    // some code that depends on included files
    // note that all included files can be in the same private scope
})();

그리고…

자동 단위 테스트를 설정하려면 WysiHat과 함께 제공된 Rakefile을 살펴보십시오. 좋은 물건 🙂

그리고 지금 답을 위해

이것은 원래의 질문에 잘 대답하지 못합니다. 나는 그것을 알고 미안하지만, 나는 그것을 다른 사람이 그들의 혼란을 조직하는 데 유용 할 수 있기를 바랍니다.

문제에 대한 나의 접근 방식은 가능한 많은 객체 지향 모델링을 수행하고 구현을 다른 파일로 분리하는 것입니다. 그런 다음 처리기는 가능한 짧아야합니다. List싱글 톤을 사용한 예제 도 좋습니다.

그리고 네임 스페이스는 … 더 깊은 객체 구조로 모방 될 수 있습니다.

if (typeof org === 'undefined') {
    var org = {};
}

if (!org.hasOwnProperty('example')) {
    org.example = {};
}

org.example.AnotherObject = function () {
    // constructor body
};

나는 모방을 좋아하지는 않지만 전역 범위를 벗어나고 싶은 많은 객체가있는 경우 도움이 될 수 있습니다.


답변

코드 구성에는 규칙 및 문서 표준을 채택해야합니다.
1. 실제 파일의 네임 스페이스 코드;

Exc = {};

2.이 네임 스페이스에서 클래스를 자바 스크립트로 묶습니다.
3. 실제 객체를 나타내는 프로토 타입 또는 관련 함수 또는 클래스를 설정합니다.

Exc = {};
Exc.ui = {};
Exc.ui.maskedInput = function (mask) {
    this.mask = mask;
    ...
};
Exc.ui.domTips = function (dom, tips) {
    this.dom = gift;
    this.tips = tips;
    ...
};

4. 코드를 개선하기위한 규칙을 설정하십시오. 예를 들어, 모든 내부 함수 또는 메소드를 오브젝트 유형의 클래스 속성으로 그룹화하십시오.

Exc.ui.domTips = function (dom, tips) {
    this.dom = gift;
    this.tips = tips;
    this.internal = {
        widthEstimates: function (tips) {
            ...
        }
        formatTips: function () {
            ...
        }
    };
    ...
};

5. 네임 스페이스, 클래스, 메소드 및 변수를 문서화하십시오. 필요한 경우 일부 코드 (일부 FI 및 Fors)는 일반적으로 코드의 중요한 논리를 구현합니다.

/**
  * Namespace <i> Example </i> created to group other namespaces of the "Example".  
  */
Exc = {};
/**
  * Namespace <i> ui </i> created with the aim of grouping namespaces user interface.
  */
Exc.ui = {};

/**
  * Class <i> maskdInput </i> used to add an input HTML formatting capabilities and validation of data and information.
  * @ Param {String} mask - mask validation of input data.
  */
Exc.ui.maskedInput = function (mask) {
    this.mask = mask;
    ...
};

/**
  * Class <i> domTips </i> used to add an HTML element the ability to present tips and information about its function or rule input etc..
  * @ Param {String} id - id of the HTML element.
  * @ Param {String} tips - tips on the element that will appear when the mouse is over the element whose identifier is id <i> </i>.
  */
  Exc.ui.domTips = function (id, tips) {
    this.domID = id;
    this.tips = tips;
    ...
};

이것들은 몇 가지 팁이지만 코드 구성에 크게 도움이되었습니다. 성공하려면 훈련이 있어야합니다!


답변

좋은 OO 디자인 원칙과 디자인 패턴을 따르면 코드를 쉽게 유지 관리하고 이해하는 데 많은 도움이됩니다. 그러나 최근에 내가 발견 한 가장 좋은 것 중 하나는 발행 / 구독이라고하는 신호와 슬롯입니다. 한 번 봐 가지고 http://markdotmeyer.blogspot.com/2008/09/jquery-publish-subscribe.html
간단한 jQuery를 구현합니다.

이 아이디어는 GUI 개발을 위해 다른 언어로 잘 사용됩니다. 코드 어딘가에 중요한 일이 발생하면 다른 객체의 다른 메소드가 구독 할 수있는 전역 합성 이벤트를 게시합니다. 이것은 객체의 탁월한 분리를 제공합니다.

Dojo (및 프로토 타입?)에는이 기술의 기본 제공 버전이 있다고 생각합니다.

또한 참조 신호와 슬롯은 무엇입니까?


답변

이전 작업에서 Javascript 모듈 패턴 을 Ext JS 응용 프로그램에 성공적으로 적용 할 수있었습니다 . 멋지게 캡슐화 된 코드를 만드는 간단한 방법을 제공했습니다.