zoukankan      html  css  js  c++  java
  • JavaScript---js的模块化

      

      js的模块模式被定义为给类提供私有和公共封装的一种方法,也就是我们常说的“模块化”。

        怎么实现“模块化”?

          通过闭包的原理来实现“模块化”  ,具体实现:1.必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例);2.封闭函数必须返回至少一个内部函数(返回多个函数时,以对象字面量的形式返回)

          先看一个实例:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>Document</title>
     6 </head>
     7 <body>
     8     <script>
     9         function Module (){
             //内部变量
    10 var something = 'cool'; 11 var another = [1,2,3]; 12        //内部函数 13 function doSomething(){ 14 console.log(something); 15 } 16 17 function doAnother(){ 18 console.log(another); 19 } 20        //返回对象字面量形式,里面包含内部函数的引用, 这样就保持了内部变量是隐藏且私有的状态。 21 return { 22 doSomething: doSomething, 23 doAnother: doAnother 24 }; 25 } 26      //调用外部函数Module创建一个模块实例foo 27 var foo = Module(); 28 foo.doSomething();//cool 29 foo.doAnother();//[1,2,3] 30 </script> 31 </body> 32 </html>

      简单分析一下代码:

          首先,Module只是一个函数,必须通过他才能创建一个模块实例,如果不执行他,内部作用域和闭包都无法被创建。 其次,Module函数返回一个字面量对象,这个返回的对象含有对内部函数而不是内部变量的引用。这样就保持了内部变量是隐藏且私有的状态。可以将这个对象类型的返回值看作模块的公共API 这个API最终会被赋值给外部的变量foo,通过他就可以访问API中的属性方法,比如:foo.doSomething()。

      上面的实例中,Module函数可以调用任意多次,每次调用都会创建一个新的模块实例。当只需要一个实例时,可以对这个模块进行简单的改进来实现单例模式:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <script>
            var foo = (function Module (){
                var something = 'cool';
                var another =  [1,2,3];
    
                function doSomething(){
                    console.log(something);
                }
    
                function doAnother(){
                    console.log(another);
                }
    
                return {
                    doSomething: doSomething,
                    doAnother: doAnother
                };
            })();
    
            foo.doSomething();//cool
            foo.doAnother();//[1,2,3]
        </script>
    </body>
    </html>

      通过将模块函数转换为IIFE(立即执行函数),立即调用这个函数并将返回值直接赋值给电力的模块实例foo

      模块也是普通的函数,因此可以接收参数:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <script>
            // var foo = (function Module (){
            //     var something = 'cool';
            //     var another =  [1,2,3];
    
            //     function doSomething(){
            //         console.log(something);
            //     }
    
            //     function doAnother(){
            //         console.log(another);
            //     }
    
            //     return {
            //         doSomething: doSomething,
            //         doAnother: doAnother
            //     };
            // })();
    
            // foo.doSomething();//cool
            // foo.doAnother();//[1,2,3]
    
            var foo = (function Module(id){
                function change(){
                    publicAPI.id = id2;
                 }
    
                 function id1(){
                     console.log(id);
                 }
    
                 function id2(){
                     console.log(id.toUpperCase());
                 }
    
                 var publicAPI = {
                     change: change,
                     id: id1
                 };
    
                 return publicAPI;
            })('hello');
    
            foo.id();//hello
            foo.change();
            foo.id();//HELLO
        </script>
    </body>
    </html>

      可以看出:通过在模块实例的内部保留公共API对象的内部引用(API指的是引用return回来的字面量对象 {...}),可以从内部模块实例进行修改,包括添加、删除方法和属性,以及修改它们的值。

      现代的模块机制

        大多数模块依赖加载器/管理器,本质上都是将模块定义为封装进一个API。 现在,宏观了解一下模块机制:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <script>
            var myModule = (function Module(){
                var modules = [];
           //定义一个define函数用于定义一个模块
                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
                };
            })();
        </script>
    </body>
    </html>

      这段代码的核心就是:modules[name] = impl.apply(impl, deps)。 为了模块的定义(define函数)引入包装函数(可以传入任何依赖),并且将返回值,也就是模块的API,存储在一个根据名字来管理的模块列表中。(不是很理解啊??)

      下面展示了如何使用它来定义模块:

      

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <script>
            var myModule = (function Module(){
                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
                };
            })();
    
            myModule.define('bar', [], function(){
                function hello(who){
                    return "Hello," + who; 
                };
    
                return{
                    hello:hello
                };
            });
    
            myModule.define('foo', ['bar'], function(bar){
                var hungry = 'hippo';
    
                function awesome(){
                    console.log(bar.hello(hungry).toUpperCase());
                };
    
                return {
                    awesome: awesome
                };
            });
    
            var bar = myModule.get('bar');
            var foo = myModule.get('foo');
    
            console.log(bar.hello('hippo'));//hello, hippo
            foo.awesome();//HELLO, HIPPO 
        </script>
    </body>
    </html>

      ‘foo’和‘bar’模块都是通过一个返回公共API的函数来定义的。‘foo’甚至接受‘bar’的实例作为依赖参数,并使用它。

        这就是模块的威力!! 

      总结一下:模块并不是什么神秘的东西,他只是一个外部函数返回内部函数的引用(字面量对象的形式返回),从而可以访问内部函数和变量的一种方式。

                                  ---摘自《你不知道的JavaScript》(上)   2017-3-22  23:24

  • 相关阅读:
    弹出层
    浅析.Net下的多线程编程
    网站新闻模块中应用装饰模式
    通过MVC模式将Web视图和逻辑代码分离
    得到任意网页源代码 (利用WebClient和WebRequest类)
    ASP.NET网站部署问题集
    什么是url重写
    C#基础概念二十五问(一)
    ASP.NET Memory:如果你的应用已经在生产环境中,那为什么还要debug=true
    Go Gob编码
  • 原文地址:https://www.cnblogs.com/first-time/p/6597707.html
Copyright © 2011-2022 走看看