Title: 01--javascript模块化进程 · Issue #1 · simplexcspp/JavaScript-Module · GitHub
Open Graph Title: 01--javascript模块化进程 · Issue #1 · simplexcspp/JavaScript-Module
X Title: 01--javascript模块化进程 · Issue #1 · simplexcspp/JavaScript-Module
Description: 一、早期javascript模块的基本写法 什么模块? 最简单的理解: 实现特定功能的一组方法 1、模块的原始写法 function m1(){ // your code } function m2(){ // your code } m1和m2组成一个模块,使用时直接调用。这种原始方式的模块形式,缺点很明显: 污染了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系。 2、模块的对象写法: 针对上面原始写法的缺点,将模块写成一个对象,所有模块...
Open Graph Description: 一、早期javascript模块的基本写法 什么模块? 最简单的理解: 实现特定功能的一组方法 1、模块的原始写法 function m1(){ // your code } function m2(){ // your code } m1和m2组成一个模块,使用时直接调用。这种原始方式的模块形式,缺点很明显: 污染了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关...
X Description: 一、早期javascript模块的基本写法 什么模块? 最简单的理解: 实现特定功能的一组方法 1、模块的原始写法 function m1(){ // your code } function m2(){ // your code } m1和m2组成一个模块,使用时直接调用。这种原始方式的模块形式,缺点很明显: 污染了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关...
Opengraph URL: https://github.com/simplexcspp/JavaScript-Module/issues/1
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"01--javascript模块化进程","articleBody":"### 一、早期javascript模块的基本写法\r\n\r\n\u003e 什么模块?\r\n\u003e 最简单的理解: **实现特定功能的一组方法**\r\n\r\n- 1、模块的原始写法\r\n```\r\nfunction m1(){\r\n // your code\r\n}\r\n\r\nfunction m2(){\r\n // your code\r\n}\r\n```\r\n m1和m2组成一个模块,使用时直接调用。这种原始方式的模块形式,缺点很明显:\r\n \r\n\u003e **污染了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系。**\r\n\r\n- 2、模块的对象写法:\r\n\r\n 针对上面原始写法的缺点,将模块写成一个对象,所有模块成员都放入这个对象里,使用时直接调用此对象的方法。\r\n```\r\nvar myModule = {\r\n \r\n _count: 0,\r\n \r\n m1: function () {\r\n\r\n // your code\r\n\r\n },\r\n \r\n m2: function () {\r\n\r\n // your code\r\n\r\n } \r\n};\r\nmyModule .m1();\r\n```\r\n那么,对象写法有什么缺点?很明显:\r\n\r\n\u003e 对象写法会暴露所有模块成员,内部私有属性可以被外部改写。\r\n\r\n下面代码改写了私有属性_count的值。\r\n\r\n```\r\nmyModule._count = 100;\r\n\r\n```\r\n- 3、立即执行函数写法:\r\n\r\n 为了解决对象写法暴露所有模块成员的问题,使用立即执行函数写法,则不会暴露私有成员。\r\n\r\n```\r\nvar myModule = (function () { \r\n \r\n var _count = 0;\r\n\r\n function m1 () {\r\n\r\n // your code\r\n\r\n } \r\n\r\n function m2 () {\r\n\r\n // your code\r\n\r\n } \r\n\r\n return {\r\n\r\n m1: m1,\r\n\r\n m2: m2\r\n\r\n };\r\n})();\r\n\r\n```\r\n使用立即执行函数的写法,外部代码无法读取内部的_count变量。\r\n\r\n```\r\nconsole.log(myModule._count); // undefined\r\n\r\n```\r\n\u003e 如果一个模块很大,必须分成多个部分,又或者一个模块需要继承另一个模块,那么该如何处理?\r\n\u003e 这时候就要使用**放大模式**,如下:\r\n\r\n- 4、放大模式\r\n\r\n```\r\nvar myModule = (function (m) { \r\n \r\n // 给myModule扩展的新方法 \r\n m.m3 = function () {\r\n // your code\r\n };\r\n\r\n return m;\r\n\r\n})(myModule);\r\n\r\n```\r\n上面的代码为myModule模块添加了一个新方法m3,然后返回新的myModule模块。\r\n\r\n\u003e 在浏览器环境中,如果我们的模块的各个部分都是从网上获取的,有时无法知道哪个部分会先加载。如果采用放大模式的写法,第一个执行的部分有可能加载一个不存在空对象,该如何处理?\r\n\u003e 这时候就要使用**宽放大模式**,如下:\r\n\r\n- 5、宽放大模式\r\n\r\n```\r\n var myModule = (function (m) {\r\n\r\n // 给myModule扩展的新方法\r\n m.m3 = function () { \r\n \r\n // your code \r\n\r\n };\r\n\r\n return m;\r\n\r\n })(myModule || {});\r\n\r\n```\r\n与\"放大模式\"相比,"宽放大模式"就是立即执行函数的参数可以是空对象。这样,当从网上获取的模块异常时,就不会报错。\r\n\r\n\u003e 一个模块,应保证其独立性,模块内部最好不与程序的其他部分直接交互,如果要在模块内部调用全局变量,最好是显式地将其他变量输入模块。\r\n\r\n- 6、模块内部输入全局变量\r\n\r\n```\r\nvar myModule = (function ($) {\r\n\r\n // your code\r\n\r\n })(jQuery);\r\n\r\n```\r\n### 二、早期javascript模块的基本写法\r\n\r\n- 1、CommonJS规范背景简述\r\n\r\n早期,一开始大家都认为JS是辣鸡,没什么用,官方定义的API只能构建基于浏览器的应用程序。 随后,CommonJS API定义很多普通应用程序(主要是非浏览器的应用)使用的API,从而填补了这个空白。它的终极目标是提供一个类似Python,Ruby和Java标准库。这样的话,开发者可以使用CommonJS API编写应用程序,然后这些应用可以运行在不同的JavaScript解释器和不同的主机环境中。\r\n \r\n在兼容CommonJS的系统中,你可以使用JavaScript开发以下程序:\r\n\r\n- 服务器端JavaScript应用程序\r\n - 命令行工具\r\n- 图形界面应用程序\r\n- 混合应用程序(如,Titanium或Adobe AIR)\r\n\r\n2009年,美国程序员Ryan Dahl创造了**node.js**项目,将javascript语言用于服务器端编程,这标志Javascript模块化编程正式诞生。\r\n\r\n在浏览器环境下,没有模块也不是特别大的问题,毕竟网页程序的复杂性有限;但是在服务器端,一定要有模块,与操作系统和其他应用程序互动,否则根本没法编程。NodeJS是CommonJS规范的实现,webpack 也是以CommonJS的形式来书写。 **node.js的模块系统,就是参照CommonJS规范实现的**。\r\n\r\n- 2、CommonJS规范简介\r\n\r\n在CommonJS中,有一个全局性方法`require()`,用于加载模块。假定有一个模块为`math.js`,就可以像下面这样加载:\r\n\r\n```\r\nvar math = require('math');\r\n\r\n```\r\n\r\n 然后,就可以调用模块提供的方法:\r\n\r\n```\r\nvar math = require('math');\r\nmath.add(2,3); \r\n```\r\n**CommonJS定义的模块分为**:\r\n\r\n - 模块引用require\r\n - 模块定义exports\r\n - 模块标识module\r\n\r\n\u003e require用来引入外部模块;exports对象用于导出当前模块的属性和方法,是唯一的出口;module对象代表模块本身。\r\n\r\n- 3、AMD规范背景\r\n\r\n基于commonJS规范的nodeJS出来以后,服务端的模块概念已经形成,很自然地,大家就想要客户端模块。而且最好两者能够兼容,一个模块不用修改,在服务器和浏览器都可以运行。但是,由于一个重大的局限,使得CommonJS规范不适用于浏览器环境。还是上面的代码,如果在浏览器中运行,会有一个很大的问题。什么问题?\r\n\r\n```\r\nvar math = require('math');\r\nmath.add(2,3); \r\n\r\n```\r\n\r\n第二行`math.add(2, 3)`,在第一行`require('math')`之后运行,因此必须等`math.js`加载完成。也就是说,如果加载时间很长,整个应用就会停在那里等,这对服务器端不是一个问题,因为所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间。但是,对于浏览器,这却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于\"**假死**\"状态。\r\n\r\n 浏览器端的模块,不能采用\"**同步加载**\"(synchronous),只能采用\"**异步加载**\"(asynchronous),这就是AMD规范诞生的背景。其是 **RequireJS**在推广过程中对模块定义的规范化产出。\r\n\r\n\u003e CommonJS是主要为了JS在服务端的表现制定的,他是不适合客户端(浏览器)的,AMD(异步模块定义)出现了,它就主要为客户端JS的表现制定规范。\r\n\r\n- 4、AMD规范简介\r\n\r\n AMD是\"Asynchronous Module Definition\"的缩写,意思就是\"异步模块定义\"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。**所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行**。\r\n\r\nAMD也采用`require()`语句加载模块,但是不同于CommonJS,它要求两个参数:\r\n\r\n```\r\nrequire([module], callback);\r\n\r\n```\r\n\r\n第一个参数`[module]`,是一个数组,里面的成员就是要加载的模块;第二个参数`callback`,则是加载成功之后的回调函数。如果将前面的代码改写成AMD形式,就是下面这样:\r\n\r\n```\r\nrequire(['math'], function (math) {\r\n\r\n math.add(2, 3);\r\n\r\n});\r\n\r\n```\r\n\r\n`math.add()`与`math`模块加载不是同步的,浏览器不会发生假死。所以很显然,AMD比较适合浏览器环境。\r\n\r\n- 5、CMD规范\r\n\r\n 大佬玉伯写了seajs,CMD规范 SeaJS 在推广过程中对模块定义的规范化产出。\r\n\r\n- 6、AMD、CMD规范异同\r\n\r\nAMD(requirejs)和 CMD (seajs)都是模块加载器,倡导模块化开发理念,核心价值是让 JavaScript 的模块化开发变得简单自然。\r\n\r\n区别:\r\n\r\n- 对于依赖的模块,AMD**提前执行**(即时加载),CMD是**延迟执行**(按需加载)\r\n\r\n- CMD推崇**依赖就近**,AMD推崇**依赖前置**,如下:\r\n\r\n```\r\n// CMD\r\ndefine(function(require, exports, module) { \r\n\r\n var a = require('./a') \r\n\r\n a.doSomething() \r\n\r\n // ...\r\n\r\n var b = require('./b') \r\n\r\n // 依赖可以就近书写 \r\n\r\n b.doSomething() \r\n\r\n // ... \r\n\r\n})\r\n\r\n// AMD \r\ndefine(['./a', './b'], function(a, b) { \r\n\r\n // 依赖必须一开始就写好 \r\n\r\n a.doSomething() \r\n\r\n // ... \r\n\r\n b.doSomething() \r\n // ... \r\n })\r\n\r\n```\r\n\r\n- AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹。\r\n\r\n**主要参考资料**:\r\n\r\n- [阮大师播客有关模块化介绍](http://www.ruanyifeng.com/home.html)\r\n- [CommonJS规范](http://javascript.ruanyifeng.com/nodejs/module.html#toc0)\r\n- [requirejs](https://github.com/requirejs/requirejs)\r\n- [seajs](https://seajs.github.io/seajs) \r\n- [AMD 和 CMD 的区别](https://www.zhihu.com/question/20351507)\r\n- [前端模块化开发的价值](https://github.com/seajs/seajs/issues/547)\r\n\r\n\r\n","author":{"url":"https://github.com/simplexcspp","@type":"Person","name":"simplexcspp"},"datePublished":"2018-02-24T13:28:34.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/1/JavaScript-Module/issues/1"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:2f098527-6758-06da-8751-58f1b759b60f |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | CCB4:F135E:2CA435:3C0647:6A6270DA |
| html-safe-nonce | f00e05384b7c8a4ec78d6eb7d2551a859dbc2c9c128f09e5e33bd5040a5ad3b9 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJDQ0I0OkYxMzVFOjJDQTQzNTozQzA2NDc6NkE2MjcwREEiLCJ2aXNpdG9yX2lkIjoiNTY4MTY5MzM2MTU1ODQxNzYyNiIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 532a71c7f0b347428427007fd369a596725a30b9b2a9efe10e417a07434e3710 |
| hovercard-subject-tag | issue:299941187 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/simplexcspp/JavaScript-Module/1/issue_layout |
| twitter:image | https://opengraph.githubassets.com/ec2c758755cc5c1feff9920a6430e4a4bc8656753b386a3f01fa970528877034/simplexcspp/JavaScript-Module/issues/1 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/ec2c758755cc5c1feff9920a6430e4a4bc8656753b386a3f01fa970528877034/simplexcspp/JavaScript-Module/issues/1 |
| og:image:alt | 一、早期javascript模块的基本写法 什么模块? 最简单的理解: 实现特定功能的一组方法 1、模块的原始写法 function m1(){ // your code } function m2(){ // your code } m1和m2组成一个模块,使用时直接调用。这种原始方式的模块形式,缺点很明显: 污染了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | simplexcspp |
| hostname | github.com |
| expected-hostname | github.com |
| None | 19769ef9d383a84eeab48bb9b309078c20f4532b73eae2f9713b18406513e0ad |
| turbo-cache-control | no-preview |
| go-import | github.com/simplexcspp/JavaScript-Module git https://github.com/simplexcspp/JavaScript-Module.git |
| octolytics-dimension-user_id | 24514952 |
| octolytics-dimension-user_login | simplexcspp |
| octolytics-dimension-repository_id | 122742245 |
| octolytics-dimension-repository_nwo | simplexcspp/JavaScript-Module |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 122742245 |
| octolytics-dimension-repository_network_root_nwo | simplexcspp/JavaScript-Module |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 76dc6b11f13eaeec1329217c9f16c262ade27a1e |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width