JS 模块 p6

利用了闭包的模块:

简单模块例子:

function fn(){
   var x = 1; 
   function y(){
       console.log(x);
    }   
 
    return {  y:y}
}
var do1 = fn()

do1.y(); // 1

我们可以将这个“对象类型”的返回值看做是 模块的公共API 
这个例子中返回的实例中 y() 等于是拥有了函数fn的内部作用域的闭包。

模块模式条件(书):

1.必须由外部的封闭函数,且被调用。

2.封闭函数必须返回至少一个内部函数

 

单例模式(平时使用的比较多):

var single = (function(){
    var x = 1;
    function fn(){
        console.log(1);
    };   
    return {  fn:fn  }
})();

single.fn();//1

将模块函数使用IIFE 表达出来,因为是立即调用,所以此实例的标识foo为单例。😵

还有一种在初始化html的时候使用的也比较多,如下:

(function(){
  var u = {};
  u.x = function(a){
       console.log(a);
  }

  window.$custom = u;

})();

$custom.x(1);//1

使用IIFE 立即给window动态增加一个属性,$custom,因为window的变量和方法是可以隐去的,我们可以直接调用$custom实例引用的方法x,最终打印1。

 

动态修改(返回实例引用中fn与fn2都用于内部作用的闭包,所以可以在外部通过调用fn2,动态修改内部id的值):

var foo = (function(){
      var id = "hhh";
      
      function fn(){
           console.log(id);
      } 

      function fn2(){
           id = "MM"
      } 

      return {  fn:fn ,fn2:fn2  }
})();

foo.fn();//hh
foo.fn2();
foo.fn();//MM

当然了,你可以更改函数或者增加新的实例方法(之前的文章中有写 JS 创建自定义对象的方式方法

 

再来一个(引用书中的例子):

var foo = (function x(){
    var module = {};

    function def(name,arr,impl){
         for(let i = 0;i<arr.length;i++){
               // 重新定义数组中的对象
               arr[i] = module[arr[i]];
         }
         module[name] = impl.apply(impl,arr);
    }
    
    function get(n){
        return module[n];
    }

    return {def:def,get:get}
})()    

定义一个先:

// 返回一个模块对象实例
foo.def('test',[],function(){ 
  
function h(n){return '我是test内部的h函数'+n} return { h : h }; }); foo.get('test').h('hi'); // 我是test内部的h函数hi // 返回方法函数本身 foo.def('test',[],function(){ function h(n){return '我是test内部的h函数'+n} return { h : h }; }); foo.get('test')('hi'); // 我是test内部的h函数hi

两种方式,第一种内部module的get 返回一个对象实例,含有h内部函数,可以调用;

第二种返回h函数本身,通过  '()' 直接调用即可。

 

再来一个,多重调用(在上面给module定义了test后,再来一个并且利用回调函数调用test)

foo.def('test2',['test'],function(callback){
     function j(){
         console.log(callback.h('hihihihi')+'其实我是test2');
     }    
     
     return { j:j }
});

foo.get('test2').j();//我是test内部的h函数hihihihi其实我是test2

我们来分析一下,在foo.def 方法中核心的时候这句 apply(有关apply 、call和blind方面以后再表),简单说一下,apply方法把作用域第一个参数的作用域绑定或追加到调用的对象中,从何绑定this,并执行改方法,第二个参数就是执行这个方法需要的参数。

那么我们在调用def时,就是给foo中的内部对象module增加了一对键值对,module.name = impl()    这里得到impl函数执行后返回值

在调用get的时候,得到这个值,在第一个def中是test返回是 {h:h} 对象实例(调用foo.get()),所以我们使用 foo.get('test').h() 就调用了返回实例中的h函数,而h函数拥有访问h所在的作用域的闭包。

再来看第二个def,test2:

第二个def时我们给到3个参数,test,[test2]和一个匿名函数

foo在执行def方法时,首先循环数组,并重新对数组中的值进行重新赋值,这个例子中是 module[test],等于是得到了def1中的{h:h} 对象实例,然后调用apply方法,执行定义的匿名函数,返回值为 {j:j}

并且j方法中的callback 其实就是{h,h} ,(是这样的  module[test2] = impl.apply(impl,{h:h}) ),明白没?

所以foo中的内部对象 module又获得了一对简直,module.test2 = { j:j }  ,并且j中的callback 是 {h:h}

最后我们通过  foo.get('test2') 获得了{j:j} 然后执行 j() 方法,并成功打印  “我是test内部的h函数hihihihi其实我是test2”。

 

此处在test2中,j()方法拥有作用域的闭包,也就是说可以访问到callback,而callback实际上在此事{h:h},而h也拥有其作用域的闭包。

可以说,这就是一种模块的表现方式或者说闭包的应用。

 

关于es6对模块有了重新的定义,再次我简单记录一下:

// test.js
function h(){
  return 'ggggg'
}

export h;

// test2.js
import h from 'test';

function j(){
   console.log(
      h();
   )
}

export j;

// foo.js
module test from 'test';
module test2 from 'test2';

console.log(
    test2.h();
)

test2.j();

关键字:

import: 将一个模块的一个或者多个API 导入到当前作用域

export: 将当前的一个标识符导出为API

module: 将模块的API 导入并绑定到一个变量。

 

posted @ 2019-01-30 13:20  李鹏飞ONLINE  阅读(207)  评论(0编辑  收藏  举报