기본 지식
우선 모듈 모드에 대한 개요를 알아야 합니다(YUI의 Eric Miraglia가 2007년 블로그에서 제안함). 이미 모듈 모드에 익숙하다면, 이 부분을 건너뛰고 "고급" 모델을 직접 읽어도 됩니다.
관련 학습 권장사항: javascript 비디오 튜토리얼
익명 함수 클로저
익명 함수 클로저는 JavaScript의 최고의 기능입니다. 이제 익명 함수를 생성하고 즉시 실행해 보겠습니다. 함수의 모든 코드는 클로저에서 실행되며 클로저는 전체 실행 프로세스 동안 이러한 코드의 개인 정보 보호 및 상태를 결정합니다.
코드는 다음과 같습니다.
(function () { // ... all vars and functions are in this scope only // still maintains access to all globals }());
익명 함수 외부의 괄호에 주의하세요. 이는 JavaScript에서 function으로 시작하는 문은 일반적으로 함수 선언으로 간주되기 때문입니다. 바깥쪽 괄호를 추가하면 함수 표현식이 생성됩니다.
Global import
JavaScript에는 숨겨진 전역 변수라는 기능이 있습니다. 변수 이름이 사용되면 컴파일러는 변수를 선언하기 위해 var를 사용하여 명령문을 찾습니다. 찾을 수 없는 경우 변수는 전역으로 간주됩니다. 할당 중에 이와 같이 사용하면 전역 범위가 생성됩니다. 이는 익명 클로저에서 전역 변수를 생성하는 것이 매우 쉽다는 것을 의미합니다. 불행하게도 전역 변수가 파일에 선언되지 않은 경우 프로그래머가 명확하지 않기 때문에 코드 관리가 불가능해질 수 있습니다. 다행히 익명 함수는 또 다른 옵션을 제공합니다. 익명 함수의 매개변수를 통해 전역 변수를 코드로 가져올 수 있는데, 이는 더 빠르고 깔끔합니다.
코드는 다음과 같습니다.
(function ($, YAHOO) { // now have access to globals jQuery (as $) and YAHOO in this code }(jQuery, YAHOO));
모듈 내보내기
때로는 전역 변수를 사용하고 싶지 않지만 선언하고 싶을 때가 있습니다. 익명 함수의 반환 값을 통해 쉽게 내보낼 수 있습니다. 모듈 패턴의 기본 내용에 대한 내용은 여기까지입니다. 여기에는 좀 더 복잡한 예가 나와 있습니다.
코드는 다음과 같습니다.
var MODULE = (function () { var my = {}, privateVariable = 1; function privateMethod() { // ... } my.moduleProperty = 1; my.moduleMethod = function () { // ... }; return my; }());
여기서 MODULE이라는 전역 모듈을 선언합니다. 이 모듈에는 MODULE.moduleMethod라는 메서드와 MODULE.moduleProperty라는 변수라는 두 가지 공개 속성이 있습니다. 또한 익명 함수의 폐쇄를 통해 비공개 내부 상태를 유지합니다. 물론 앞서 언급한 모드를 사용하여 필요한 전역 변수를 쉽게 가져올 수도 있습니다
고급 모드
앞서 언급한 콘텐츠는 이미 많은 요구 사항을 충족할 수 있습니다. 필요하지만 이 패턴을 더 깊이 파고들어 강력한 확장 가능한 구조를 만들 수 있습니다. MODULE이라는 모듈을 통해 조금씩 배워보도록 하겠습니다.
Expansion
현재 모듈 모드의 한 가지 제한 사항은 전체 모듈을 하나의 파일에 작성해야 한다는 것입니다. 대규모 코드 개발을 해본 사람이라면 누구나 한 파일을 여러 파일로 분리하는 것의 중요성을 알고 있습니다. 다행스럽게도 모듈을 확장할 수 있는 좋은 방법이 있습니다. 먼저 모듈을 가져온 다음 속성을 추가하고 마지막으로 내보냅니다. 여기서의 예는 위에서 언급한 방법을 사용하여 MODULE을 확장하는 것입니다.
코드는 다음과 같습니다.
var MODULE = (function (my) { my.anotherMethod = function () { // added method... }; return my; }(MODULE));
불필요하지만 일관성을 위해 다시 var 키워드를 사용합니다. 그런 다음 코드가 실행되고 모듈은 MODULE.anotherMethod라는 공개 메서드를 추가합니다. 확장 파일은 또한 자체 비공개 내부 상태를 유지하고 가져옵니다.
느슨한 확장
위의 예에서는 먼저 모듈을 만든 다음 모듈을 확장해야 하는데 이는 필요하지 않습니다. 스크립트를 비동기적으로 로드하는 것은 Javascript 애플리케이션의 성능을 향상시키는 가장 좋은 방법 중 하나입니다. . 느슨한 확장을 통해 어떤 순서로든 로드할 수 있고 여러 파일로 나눌 수 있는 유연한 모듈을 만듭니다. 각 파일의 구조는 대략 다음과 같습니다
코드는 다음과 같습니다.
var MODULE = (function (my) { // add capabilities... return my; }(MODULE || {}));
이 모드에서는 var 문이 필수입니다. 가져온 모듈이 없으면 생성됩니다. 이는 LABjs와 같은 도구를 사용하여 이러한 모듈 파일을 병렬로 로드할 수 있음을 의미합니다.
긴밀한 확장
느슨한 확장도 좋지만 모듈에 몇 가지 제한 사항이 추가됩니다. 가장 중요한 점은 모듈 속성을 안전하게 재정의할 수 있는 방법이 없으며 초기화 중에는 다른 파일에서 모듈 속성을 사용할 수 없다는 것입니다(그러나 초기화 후 런타임에는 사용할 수 있습니다). 컴팩트 확장에는 특정 로딩 순서가 포함되어 있지만 다시 쓰기를 지원합니다(원래 MODULE 확장).
코드는 다음과 같습니다.
var MODULE = (function (my) { var old_moduleMethod = my.moduleMethod; my.moduleMethod = function () { // method override, has access to old through old_moduleMethod... }; return my; }(MODULE));
여기서 MODULE.moduleMethod를 다시 작성하고 필요에 따라 원래 메서드에 대한 참조를 유지했습니다.
복사 및 상속
코드는 다음과 같습니다.
var MODULE_TWO = (function (old) { var my = {}, key; for (key in old) { if (old.hasOwnProperty(key)) { my[key] = old[key]; } } var super_moduleMethod = old.moduleMethod; my.moduleMethod = function () { // override method on the clone, access to super through super_moduleMethod }; return my; }(MODULE));
这种模式可能是最不灵活的选择。虽然它支持了一些优雅的合并,但是代价是牺牲了灵巧性。在我们写的代码中,那些类型是对象或者函数的属性不会被复制,只会以一个对象的两份引用的形式存在。一个改变,另外一个也改变。对于对象来说[g5] ,我们可以通过一个递归的克隆操作来解决,但是对于函数是没有办法的,除了eval。然而,为了完整性我还是包含了它。
跨文件的私有状态
把一个module分成多个文件有一很大的局限,就是每一个文件都在维持自身的私有状态,而且没有办法来获得其他文件的私有状态。这个是可以解决的,下面这个松拓展的例子,可以在不同文件中维持私有状态。
代码如下:
var MODULE = (function (my) { var _private = my._private = my._private || {}, _seal = my._seal = my._seal || function () { delete my._private; delete my._seal; delete my._unseal; }, _unseal = my._unseal = my._unseal || function () { my._private = _private; my._seal = _seal; my._unseal = _unseal; }; // permanent access to _private, _seal, and _unseal return my; }(MODULE || {}));
每一个文件可以为它的私有变量_private设置属性,其他文件可以立即调用。当module加载完毕,程序会调用MODULE._seal(),让外部没有办法接触到内部的 _.private。如果之后module要再次拓展,某一个属性要改变。在载入新文件前,每一个文件都可以调用_.unsea(),,在代码执行之后再调用_.seal。
这个模式在我今天的工作中想到的,我从没有在其他地方见到过。但是我认为这是一个很有用的模式,值得单独写出来。
Sub-modules
最后一个高级模式实际上是最简单的,有很多创建子module的例子,就像创建一般的module一样的。
代码如下:
MODULE.sub = (function () { var my = {}; // ... return my;}());
虽然这可能是很简单的,但是我决定这值得被写进来。子module有一般的module所有优质的特性,包括拓展和私有状态。
总结
大多数高级模式都可以互相组合来创建更有用的新模式。如果一定要让我提出一个设计复杂应用的方法的话,我会结合松拓展,私有状态,和子module。
在这里我没有提到性能相关的事情,但是我可以说,module模式对于性能的提升有好处。它可以减少代码量,这就使得代码的载入更迅速。松拓展使得并行加载成为可能,这同样提升的载入速度。初始化的时间可能比其他的方法时间长,但是这多花的时间是值得的。只要全局变量被正确导入了运行的时候就不会出问题,在子module中由于对变量的引用链变短了可能也会提升速度。
最后,这是一个子module自身动态加载的例子(如果不存在就创建),为了简介我没有考虑内部状态,但是即便考虑它也很简单。这个模式可以让复杂,多层次的代码并行的加载,包括子module和其他所有的东西。
代码如下:
var UTIL = (function (parent, $) { var my = parent.ajax = parent.ajax || {}; my.get = function (url, params, callback) { // ok, so I'm cheating a bit return $.getJSON(url, params, callback); }; // etc... return parent; }(UTIL || {}, jQuery));
我希望这些内容是有用的,请在下面留言来分享你的想法。少年们,努力吧,写出更好的,更模块化的JavaScript。
위 내용은 JavaScript의 모듈 패턴 프로그래밍에 대한 심층 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!