当前位置: 首页 > Web前端 > HTML5

为什么前端需要模块化开发

时间:2023-04-05 23:47:16 HTML5

写在开头前端的开发总会让我们眼前一亮。什么规格出来了?我还没有完全理解最后的规范。但不管未来如何发展,了解历史还是很重要的。以史为鉴,方可知得失。只有了解规范的发展历史,才能更好地理解当前的规范。没有模块化的前端代码会怎样?变量和方法不易维护,容易污染全局作用域。加载资源的方式是从上到下通过script标签。根据环境的主观逻辑,代码越多越复杂。大型项目资源难以维护,尤其是多人合作的情况下,引入资源会让人崩溃。我们当时是怎么引入资源的。看上面的script标签,是不是感觉很眼熟。通过脚本引入你想要的资源,从上到下的顺序,顺序很重要,资源的加载决定了你的代码能否运行。当然我们还没有添加defer和async属性,否则加载逻辑会比较复杂。这里介绍的资源还是比较少的,太多的script标签会造成请求过多。同时,项目越大,最后依赖越复杂,维护难度大,依赖模糊,请求太多。全球污染的可能性会更大。那么问题来了,如何形成一个独立的scope呢?defer和asyncdefer的区别,直到整个页面在内存中正常渲染后才会执行(DOM结构完全生成,其他脚本执行完毕);一旦异步下载,渲染引擎将中断渲染。执行此脚本后,继续渲染。一句话,defer是“渲染后执行”,async是“下载后执行”。另外,如果有多个defer脚本,会按照它们在页面出现的先后顺序加载,而多个async脚本不能保证加载顺序。模块化的基石,立即调用的函数表达式(简称IIFE),其实就是一个javaScript函数。函数内部可以定义方法和私有属性,相当于一个封闭的作用域。例如下面的代码:()//myselfmodule._private//undefined上面的代码可以形成一个独立的作用域,一定程度上可以减少全局污染的可能性。这种表示法是现代模块化的基石。虽然可以定义方法,但不能定义属性。这时候,各种前端规范相继出现。首先出现的是common.js。最先遵守CommonJS规范的是node.js。这个改动让服务端可以用js写。我们的javaScript不局限于浏览器端,服务器端也能分得一杯羹。它被称为模块化的第一个里程碑。想想两万五千人的长征,第一个里程碑在哪里?CommomJS模块的特点模块中的代码只会在模块范围内运行,不会污染全局范围。模块可以多次引入,但第一次加载时只会运行一次,后续操作会被缓存。价值。要使模块再次工作,必须清除缓存。//删除指定模块的缓存deleterequire.cache[moduleName];//删除所有模块的缓存Object.keys(require.cache).forEach(function(key){deleterequire.cache[key];})模块的加载顺序遵循它们在代码中出现的顺序。为什么少用exportsexports只是一个指向module.exports的变量,即exports只是一个引用。所以在对外导出模块的时候,我们可以通过exports来添加方法和属性。通过module.exports对外输出,其实就是读取module.exports的变量。但是在使用exports的时候要非常小心,因为稍有不慎就会切断与module.exports的连接。例如:exports=function(x){console.log(x)};上面代码运行后,exports不再指向module.exports。如果难以分辨清楚,一般最好不要用exports,直接用module.exports。如何区分模块是直接执行还是调用执行。require.mainAPI有这样的作用。如果直接执行模块,则require.main属性指向模块本身。比如下面这样:require.main===module为什么客户端不使用commonjs规范?我们知道客户端(浏览器)主要通过网络加载资源,一般在本地读取较少,而node.js主要用于服务端编程,模块文件一般存在本地硬盘,然后I/O读取Fetching速度很快,所以连同步加载都适用,浏览器加载资源必须异步获取,比如常见的ajax请求。这时候AMD的规格就很合适了。模块可以异步加载,并且允许回调函数。client规范不仅是AMD,还有CMD。每种规格的兴起背后总有一些原因。requirejs的火爆是因为commonjs不能满足我们的需求。之所以创建sea.js,也是因为requirejs不能满足一些场景。AMD和CMD-AMDCMD的区别原理define(id?,dependencies?,factory)定义了一个单独的函数“define”。id是要定义的模块。依赖通过dependencies传入factory是一个factory参数的对象,指定模块的导出值。CMD规范与AMD类似,尽可能简单,但更兼容common.js。优点特别适合浏览器环境下的异步加载,可以并行加载。依靠预执行,提前执行。在定义模块时,可以明确声明自己所依赖的模块依赖于就近和延迟执行。按需加载,并在需要时要求。缺点:开发成本高,模块定义的语义难以理解,与采用的模块化思维方式不太一致。依赖SPM封装,模块加载主观逻辑重。体现require.jssea.jsES6让前端模块化触手可及。ES6模块不是对象,导入语法会被JavaScript引擎静态分析。请注意,这是一个非常重要的功能。我们平时使用commonjs的时候,代码是在运行时加载的,而es6是在编译时引入模块代码。当然,我们现在的浏览器还没有这么强大的功能。我们需要借助各种编译工具(webpack)才能以正确的姿势使用es6的模块化。功能。也是因为编译时可以引入模块代码,从而实现静态分析。ES6模块化的优点是什么静态编译如果可以静态化,编译时就可以确定模块的依赖关系,以及输出和输入变量,然后CommonJS、AMD、CMD只能在编译时确定这些关系代码正在运行。不需要特殊的UMD模块格式不再需要UMD模块格式,未来服务器和浏览器都会支持ES6模块格式。目前各种工具库(webpack)其实已经做到了这一点。各种当前的全局变量都可以模块化。比如navigator现在是一个全局变量,以后可以模块化加载。这消除了将对象作为名称空间的需要。需要注意的是,export语句输出的接口通过import导入后,其对应的值是动态绑定的,即即使模块中的值发生变化,仍然可以获得实时值。commonJS模块的输出是值的缓存,没有动态更新。由于es6最初的设计是静态优化,export命令不能在block-level范围内。如果出现就会报错,所以导出一般写在底部或者顶部。functionfun(){exportdefault'hello'//SyntaxError}import命令有提升作用,会提升到整个模块的头部首先执行。例如:fun()从'myModule'导入{fun};上面代码import的执行时间早于fun调用,因为import命令是在编译阶段执行的,也就是在代码运行之前。exportdefault使用exportdefault就是导出一个名为default的变量或方法,然后系统允许你给它取任何名字。所以,你可以看到下面的文字。//modules.jsfunctionadd(x,y){returnx*y}export{addasdefault};//相当于exportdefaultadd;//app.jsimport{defaultaddfoo}from'modules';//相当于对于importfoofrom'modules',这是因为exportdefault命令实际上只输出一个名为default的变量,所以它后面不能跟变量声明语句。检测代码是否在ES6模块中的特殊技巧通过使用顶层this等于undefined的句法点,可以检测当前代码是否在ES6模块中。constisNotModuleScript=this!==undefined;如果想继续讨论或了解更多知识,欢迎加入QQ或微信讨论:854280588