>웹 프론트엔드 >JS 튜토리얼 >JS 코드의 모듈화 구현 방법

JS 코드의 모듈화 구현 방법

巴扎黑
巴扎黑원래의
2017-05-27 10:53:201706검색

모듈 모드를 사용하는 이유는 무엇입니까?

전역 범위에서 선언된 변수와 함수는 자동으로 전역 객체 Window의 속성이 되기 때문에 종종 이름 충돌이 발생합니다. 또한 매우 중요한 유지 관리 문제가 발생합니다. 전역 변수가 많을수록 버그가 발생할 확률이 높아집니다. 따라서 모듈화의 목적 중 하나는 이 문제를 해결하는 것입니다. 🎜>

전역 변수 제로 모드

이 모드는 응용 시나리오가 적고 IIFE(즉시 실행되는 익명 함수)를 사용하며 모든 코드를 래핑합니다. , 모든 변수와 함수가 함수 내부에 숨겨져 전역 세계를 오염시키지 않도록 합니다.

사용 시나리오:

    • 해당 코드가 다른 코드에 의해 신뢰되지 않는 경우

    • 런타임에 코드를 지속적으로 확장하거나 수정할 필요가 없을 때

    • 코드가 짧고 다른 코드와 상호 작용할 필요가 없는 경우

 

단일 전역 변수 모드

기본 정의

단일 전역 변수 모드는 전역 변수를 하나만 생성하는 것을 의미합니다. 변수는 가능한 변수로 지정), 전역 변수의 이름은 고유해야 하며 현재 또는 향후 내장 API와 충돌하지 않아야 합니다. 모든 기능 코드는 이 전역 변수에 마운트되어야 합니다.

다음과 같은 다양한 인기 클래스 라이브러리에서 널리 사용되었습니다.

  1. YUI는 고유한 YUI를 정의합니다. 전역 객체

  2. JQuery는 $와 JQuery라는 두 개의 전역 객체를 정의합니다.

  3. Dojo는 dojo 전역 객체

  4. Closure는 goog 전역 객체를 정의합니다.

예:

var Mymodule= {}; 
 
Mymodule.Book = function(){...}; 
Mymodule.Book.prototype.getName = function(){....}; 
 
Mymodule.Car = function(){...}; 
Mymodule.Car.prototype.getWheels = function(){....};

모듈의 정의

모듈은 일반적인 기능입니다. 새로운 전역 변수나 네임스페이스를 생성하지 않는 조각입니다. 대신 모든 코드는 이름으로 표시될 수 있으며 이 모듈은 다른 모듈에 종속될 수도 있습니다.

function CoolModule(){ 
        var something = 'cool'; 
        var another = [1,2,3]; 
        function doSomething(){ 
            console.log( something); 
        } 
        function doAnother(){ 
            console.log(another.join('!')); 
        } 
        return { 
            doSomething: doSomething, 
            doAnother: doAnother 
        }; 
} 
var foo = CoolModule(); 
foo.doSomething(); //cool 
foo.doAnother(); //1!2!3

여기 CoolModule이 있습니다. 모듈이지만 함수일 뿐입니다. 이때 모듈의 인스턴스 foo를 생성하기 위해 CoolModule 함수가 호출됩니다. (CoolModule이 객체를 반환하기 때문에 그 중 하나는 내부 속성을 참조합니다. 함수) CoolModule이 반환하는 모듈 개체는 모듈의 공개 API입니다(내부 함수를 직접 반환할 수도 있음)

따라서 모듈 패턴은 두 가지 필수 조건을 충족해야 합니다.

  1. 외부 폐쇄 함수가 있어야 하며 해당 함수는 CoolModule과 같이 적어도 한 번은 호출되어야 합니다(각 호출은 새 모듈 인스턴스를 생성합니다). 🎜>

  2. 닫힌 함수에는 하나 이상의 내부 함수가 반환되어야 합니다. 그래야 내부 함수가 프라이빗 범위에서 클로저를 형성하고 프라이빗 상태에 액세스하거나 수정할 수 있습니다.
  3. 싱글톤 모듈 패턴 구현:

var foo = ( function CoolModule(){ 
        ...//代码同上例 
})(); 
foo.doSomething(); 
foo.doAnother();
모듈 내부의 공용 API 객체에 대한 내부 참조를 유지할 수도 있습니다. , 메소드 및 속성 추가 및 삭제를 포함하여 모듈 인스턴스를 내부적으로 수정할 수 있도록

function CoolModule(){ 
    var something = 'cool'; 
    var another = [1,2,3]; 
    function change() { 
        pubicAPI.doSomething = doAnother; 
    } 
    function doSomething(){ 
        console.log( something); 
    } 
    function doAnother(){ 
        console.log(another.join('!')); 
    } 
    var pubicAPI = { 
        change: change, 
        doSomething: doSomething 
    }; 
    return pubicAPI; 
} 
var foo = CoolModule(); 
foo.doSomething(); //cool 
foo.change(); 
foo.doSomething(); //1!2!3 
var foo1 = CoolModule(); 
foo1.doSomething(); //cool

최신 모듈 메커니즘

네임스페이스는 기능 그룹을 나타내기 위해 전역 변수에 속성 ​​추가에 간단히 전달됩니다.

네임스페이스에 따라 다양한 함수를 그룹화하면 단일 전역 변수를 체계적으로 정리할 수 있으며 팀 구성원이 새 함수를 어느 섹션에 정의해야 하는지 알 수 있습니다. 또는 어느 섹션으로 이동하여 기존 함수를 찾을 수도 있습니다.

  例如:定义一个全局变量Y,Y.DOM下的所有方法都是和操作DOM相关的,Y.Event下的所有方法都是和事件相关的。

  1.   常见的用法是为每一个单独的JS文件创建一个新的全局变量来声明自己的命名空间;

  2.   每个文件都需要给一个命名空间挂载功能;这时就需要首先保证该命名空间是已经存在的,可以在单全局变量中定义一个方法来处理该任务:该方法在创建新的命名空间时不会对已有的命名空间造成破坏,使用命名空间时也不需要再去判断它是否存在。

var MyGolbal = { 
    namespace: function (ns) { 
        var parts = ns.split('.'), 
            obj = this, 
            i, len = parts.length; 
        for(i=0;i<len;i++){ 
            if(!obj[parts[i]]){ 
                obj[parts[i]] = {} 
            } 
            obj = obj[parts[i]]; 
        } 
        return obj; 
    } 
}; 
MyGolbal.namespace(&#39;Book&#39;); //创建Book 
MyGolbal.Book; //读取 
MyGolbal.namespace(&#39;Car&#39;).prototype.getWheel = function(){...}

  大多数模块依赖加载器或管理器,本质上都是将这种模块定义封装进一个友好的API

var MyModules = (function Manager() { 
    var modules = {}; 
    function define(name, deps, impl) { 
        for(var i=0; i<deps.length; i++){ 
            deps[i] = modules[deps[i]]; 
        } 
        modules[name] = impl.apply(impl,deps); 
    } 
    function get(name) { 
        return modules[name]; 
    } 
    return { 
        define: define, 
        get: get 
    }; 
})();

  以上代码的核心是modules[name] = impl.apply(impl,deps);,为了模块的定义引入了包装函数(可以传入任何依赖),并且将模块的API存储在一个根据名字来管理的模块列表modules对象中;

  使用模块管理器MyModules来管理模块:

MyModules.define(&#39;bar&#39;,[],function () { 
    function hello(who) { 
        return &#39;let me introduce: &#39;+who; 
    } 
    return{ 
        hello: hello 
    }; 
}); 
MyModules.define(&#39;foo&#39;,[&#39;bar&#39;],function (bar) { 
    var hungry = &#39;hippo&#39;; 
    function awesome() { 
        console.log(bar.hello(hungry).toUpperCase()); 
    } 
    return { 
        awesome: awesome 
    }; 
}); 
var foo = MyModules.get(&#39;foo&#39;); 
foo.awesome();//LET ME INTRODUCE: HIPPO

  异步模块定义(AMD):

define(&#39;my-books&#39;, [&#39;dependency1&#39;,&#39;dependency2&#39;],  
    function (dependency1, dependency2) { 
        var Books = {}; 
        Books.author = {author: &#39;Mr.zakas&#39;}; 
        return Books; //返回公共接口API 
    } 
);

  通过调用全局函数define(),并给它传入模块名字、依赖列表、一个工厂方法,依赖列表加载完成后执行这个工厂方法。AMD模块模式中,每一个依赖都会对应到独立的参数传入到工厂方法里,即每个被命名的依赖最后都会创建一个对象被传入到工厂方法内。模块可以是匿名的(即可以省略第一个参数),因为模块加载器可以根据JavaScript文件名来当做模块名字。要使用AMD模块,需要通过使用与AMD模块兼容的模块加载器,如RequireJS、Dojo来加载AMD模块

requre([&#39;my-books&#39;] , function(books){ 
            books.author; 
            ... 
   } 
)

  以上所说的模块都是是基于函数的模块,它并不是一个能被稳定识别的模式(编译器无法识别),它们的API语义只是在运行时才会被考虑进来。因此可以在运行时修改一个模块的API

  未来的模块机制

  ES6为模块增加了一级语法支持,每个模块都可以导入其它模块或模块的特定API成员,同样也可以导出自己的API成员;ES6的模块没有‘行内’格式,必须被定义在独立的文件中(一个文件一个模块)ES6的模块API更加稳定,由于编译器可以识别,在编译时就检查对导入的API成员的引用是否真实存在。若不存在,则编译器会在运行时就抛出‘早期’错误,而不会像往常一样在运行期采用动态的解决方案;

  bar.js

function hello(who) { 
    return &#39;let me introduce: &#39;+who; 
} 
export hello; //导出API: hello

  foo.js

//导入bar模块的hello() 
import hello from &#39;bar&#39;; 
 
var hungry = &#39;hippo&#39;; 
function awesome() { 
    console.log(hello(hungry).toUpperCase()); 
} 
export awesome;//导出API: awesome

  baz.js

//完整导入foo和bar模块 
module foo from &#39;foo&#39;; 
module bar from &#39;bar&#39;; 
foo.awesome();
  1.   import可以将一个模块中的一个或多个API导入到当前作用域中,并分别绑定在一个变量上;

  2.   module会将整个模块的API导入并绑定到一个变量上;

  3.   export会将当前模块的一个标识符(变量、函数)导出为公共API;

  4.   模块文件中的内容会被当做好像包含在作用域闭包中一样来处理,就和函数闭包模块一样;

위 내용은 JS 코드의 모듈화 구현 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.