前端模块化开发

首先啥子也不说先写一个

在es5中是没有块级作用域额概念的,,我们一般都是这么来进行模拟的


var long = (function (){

   var baobao = 1,

  bao=2;

 function long1(){}

function long2(){}

return {

   fn1 : long1,

   fn2 :long2

 }  

})()

这样的写法,我们在模块的外部无法修改我们没有暴露出来的变量,函数,上面的做法就是我们进行模块化开发的基础,

  目前来说通用的js模块化开发的规范主要有commmon.js 和AMD



common.js


 因为在网页端没有模块化变成只是页面js逻辑复杂,但是也是可以工作下去,有过或者了解服务器端的都知道,在服务器端一定要有模块化,所以虽然js在web端发展第一个流行的模块化规范却是由服务端的js应用带来的,common.js规范是有node.js发扬光大的。这也说明了js正式进入了模块化编程的舞台。



 一 定义模块 

根据common.js规范,一个单独的文件就是一个模块,每一个模块都是一个单独的作用域。通俗一点就是说,在这个模块内部定义的变量,无法被其他模块读取,除非定义为一个全局即global的对象的属性。


二 模块输出

 模块只有一个出口 。 module.exports对象,我们需要把模块希望输出的内容放入到该对象


三 加载模块

加载模块使用的就是require方法,该方法读取一个文件并执行,返回文件内部的module.exports对象



 例子 :  //模块定义为 long。js

  var name = "longbaoboao";

   function pritne(){

   console.log(name):

   }

  function   longs(){

  console.log("long"+name);

 }

module.exports = {

     pritne : pritne,

    longs : longs

  }

然后我们就可以加载模块了


  var longbb = require("long.js")

  longbb.pritne();


不同的实现对require的路径要求不同 ,一般情况下可以省略js的扩展名,可以使用相对路径,,也可以使用绝对路径,,甚至可以直接省去路径直接写模块的名字(前提是该模块是系统内置的模块)。



尴尬的浏览器

 

   仔细看上面的代码,会发现require是同步的。模块系统需要同步读取模块文件的内容,并编译执行以得到模块的内容,这个在服务器端很自然,但是要想在浏览器端实现就有很多的问题,在浏览器端,加载js最佳,最容易的方式是在document中插入script标签,但是脚本的标签天生异步,传统的common.js在浏览器环境中无法正常加载。

  解决的思路之一是: 开发一个服务器端组件,对模块代码做静态分析,将模块与他的依赖列表一起返回给浏览器,这样很好使,但是但是需要服务器安装额外的组件,并因此要调整一系列的底层结构

 另一个就是,用标准的末班来封装模块定义,但是对于模块应该怎么定义和怎么加载,又产生分歧。



AMD

 中文 : 异步模块定义  。 他是一个在浏览器端模块化开发的规范,由于不是js原生支持,使用AMD规范进行页面开发需要用到对应的库函数,也就是require.js,实际上AMD是require.js在推广过程中对模块定义的规范化产生的。

require.js 主要解决了两个问题 : 

 一 多个js文件可能有依赖关系,被依赖的文件需要早于依赖他的文件加载到浏览器。

二 js加载的时候浏览器会停止页面的渲染,加载文件越多,页面失去响应的时间越长。

 例子 

  //定义为myModule.js


define(['dependency'],function(){

       var  name = "long“;

      function printname(){

         console.log(name);

      };

   return {

       printname : printname 

    }

  })


  //加载模块

  require(["myModule],function(my){

         my.printname();

     })


其语法就是 :

 require.js 定义一个函数define 他是一个全局变量,用来定义模块。

 define(id , dependencies,factory);

    id 可选参数 用来定义模块的标示,如果没有提供该参数,脚本文件名(去掉扩展名)

   dependcies  是一个当前模块依赖的模块名称数组

   factory   工厂方法 , 模块初始化要执行的函数或对象,如果为函数,他应该只被执行一次,如果是对象,此对象应该是模块的输出值

  上面 使用require加载模块; 

    require([dependencies],function(){})

   require()函数接受两个参数

   第一个参数是一个数组 ,表示所以来的模块

  第二个参数是一个回调函数 当前面制定的模块都加载成功后,他将被调用,加载的模块会以参数的形式传入该函数,从而在毁掉函数的内部就可以使用这些模块。

require() 函数在加载依赖的函数的时候是异步加载的,这样浏览器不会失去响应,他指定的回调函数,只有前面的模块第一加载成功后,才会执行,解决了依赖性的问题



CMD  通用模块定义 

   CMD规范是在国内发展出来的, 使用的是sea.js,sea.js要解决的问题和require.js  一样,只不过在模块定义方式额模块加载(可以说运行,解析)时机上有所不同通。

  在语法上 

   sea.js 崇尚一个模块一个文件,遵循统一的写法

 define 

  define(id , deoendcies ,factory)

 因为CMD崇尚一个文件一个模块,所以经常就用文件名作为模块id;CMD崇尚模块依赖就近,所以一般不再define的参数中写依赖,而是在factory中写。

  

  factory有三个参数

  factory(require , exports , module){}

 一 require 是factory函数的第一各参数,require是一个方法,接受模块表示作为唯一参数,用来获取其他模块童工的接口。

二 exports

      exports是一个对象,用来向外提供模块的接口。

三  module

  module 是一个对象,上面积存储与当前模块相关联的一些属性和方法、


  //定义模块 myModule.js

define(function(require,exports,module){

     var $ = require("jquery.js");

     

 })

//加载模块

  seajs.use(["myModule.js"],function(my){})


AMD 和 CMD 的区别


AMD推崇的是依赖前置 在定义模块的时候就要声明其依赖的模块

CMD  推崇的就近依赖 ,只有在用到某个模块的时候再去require


AMD 和 CMD 最大的区别是对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同。

很多人说require.js是异步加载模块,sea.js是同步加载模块,这么理解实际上是不准确的,其实加载模块都是异步的,只不过AMD是依赖前置,js可以方便知道依赖模块是谁。立即加载,而CMD就近依赖,需要使用把模块变为字符串解析一遍才知道依赖了那些模块,这也是很多人诟病的CMD 的 点,牺牲性能来带来开发的便利性,实际上解析模块用的时间短到可以忽略。



为什么说两个的区别是依赖模块执行时机不同,为什么很多人认为AMD 是异步的 , CMD 是同步的。

同样是异步加载模块,AMD在加载模块完成后就会执行该模块,所有的模块都加载执行完后会进入require的回调函数中,执行主逻辑,这样的效果就是依赖模块的执行顺序和书写顺序不一定一致,看网络速度,哪个先下载下来,哪个先执行,但是主逻辑一定在所有依赖加载完成后才执行。



CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的。
这也是很多人说AMD用户体验好,因为没有延迟,依赖模块提前执行了,CMD性能好,因为只有用户需要的时候才执行的原因。 










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值