缘由

在2013-03-06 13:58的时候,曾甩下一片文章叫:《为什么不使用requirejs和seajs》,并放下豪言说发布一款完美的模块化库,再后来就把那篇文章删了,再然后就没有然后。该用seajs还用seajs,甚至我码的SCJ都是用requirejs组织起来的。

时光飞逝,岁月流转。弹指间,来到了2014年6月15日,也就是昨日,突然码兴大发,一发不可收拾,也许跟最近小说和诗写得比较猛,把码意给压抑了,便有了这次喷发。

js问题

作为一名前MS必应团队资深当耐特(.NET)石专家,拿js与C#开发应用开发做个对比,js主要暴露的问题有:

1.没有class关键字来定义类

2.没有namespace关键字来定义命名空间

3.没有using/require/import/include关键字来处理依赖

4.继承、partial class、static、private、protected、publish等都要通过小技巧或者特定约定规范且手段太多

AMD和CMD的问题

为什么要define(function(){return xx})?

为什么要本是同根生,还要deps?

为什么要module.export?

为什么要define(function(require, exports, module) {})?

为什么所有模块都需要require deps才能使用?

别看多只多写了几个单词,但这绝对是挣扎纠结之后妥协的结果。

你要推翻它?那请制定一个更好的规范,OK?没有就别瞎嚷嚷,OK?

规范

js里一切define的东西皆class创建出来的

js中一切class都在namespace下

js中define("namespace.class",[namespaces],factory)用于把namespace和class名定义好,并可引用依赖的namespace,类似C#using

js中require用于引用依赖,类似于C#using

js中同一namespace下,依赖的模块不需要引用,如define("namespace.classA",factory)不再需要define("namespace.classA",["namespace.classB"],factory)

js中继承直接通过冒号:define("namespace.class:base",[namespaces],factory)

js中部分类直接通过partial关键字define("partial namespace.class",[namespaces],factory)

ps:尼玛!要求这么多,那还是js了吗?一定要把js改成C#一样吗?直接去用cs和ts算了?规范有可行性吗?能实现吗?

恩!js是个可塑性很强的小子,你想把他塑造成什么形象,他就成什么样子。

举个栗子

define("AppName.Song", function () {var Song = function (title) {this.title = title;}
})
define("AppName.Album", function () {var Album = {};Album.title = "当耐特专辑";Album.songs = [new Song("当耐特进行曲"), new Song("当耐特荡起双桨")];
})
require(["AppName"], function () {var span = document.createElement("span"), text = "";for (var i = 0, len = arguments.length; i < len; i++) {text += "第" + i + "个参数:" + arguments[i].toString();text += "<br/>"}var song = new Song("春天的故事");text += "song title:" + song.title;text += "<br/>";text += "album first song:" + Album.songs[0].title;span.innerHTML = text;var resultShowPanel=document.getElementById("resultShowPanel");resultShowPanel.innerHTML="";resultShowPanel.appendChild(span);
})

可以在不同操作系统或浏览器环境测试,兼容到IE5.5+

从代码可以看出:

在Album中,不需要引用Song,就可以使用父AppName下的Song

在程序入口require下,直接引用top namespace就可以使用其下的Song和Album

原理

先看下图:

拿到function之后进行toString,再重构该string,然后创建新的Function,再apply执行,把赖的模块传给apply的第二个参数。有码有真相:

_findRefrence = function (deps, callback, isDefine, className, mdName) {var i = 0, len = deps.length, moduleArr = [], moduleNameArr = [];for (; i < len; i++) {for (var key in modules) {var arr = key.split("."), ns = arr[0], cl = arr[1];if (ns === deps[i]) {moduleNameArr.push(cl);moduleArr.push(modules[key]);}}}var entire = callback.toString();var body = entire.slice(entire.indexOf("{") + 1, entire.lastIndexOf("}")) + (isDefine ? ("return " + className + ";") : "");var fn = new Function(moduleNameArr, body);var obj = fn.apply(null, moduleArr);if (isDefine) {modules[mdName] = obj;}
}

此时该有掌声,但且慢着鼓掌,这是第一个版本,仅仅不够。再看下个栗子:

再举栗子

define2("NS.Song", { init: function (title) { this.title = title; var aa = "xxxxxxxxxxxx"; }, play: function () { alert(this.title); } }) define2("NS.Album", { init: function (title,songs) { this.title = title || "当耐特专辑"; this.songs =songs|| [new Song("当耐特进行曲"), new Song("当耐特荡起双桨")]; }, createSong: function (name) { var song = new Song(name); this.songs.push(song); } }) require2(["NS"], function () { var span = document.createElement("span"), text = ""; for (var i = 0, len = arguments.length; i < len; i++) { text += "第" + i + "个参数:" + arguments[i].toString(); text += "<br/>" } var song = new Song("春天的故事"); text += "song title:" + song.title; text += "<br/>"; var album = new Album(); text += "album first song:" + album.songs[0].title; span.innerHTML = text; var resultShowPanel2 = document.getElementById("resultShowPanel2"); resultShowPanel2.innerHTML=""; resultShowPanel2.appendChild(span); })

现在可以看到,define的function没有了?全部成了{init:xxx,xxx:xxx}的JSON格式,require还保留了其回掉的function,这样是符合语义的。

简直是极简主义!简单就是美。但简单的背后做了大量的工作。

原理

看图:

相关代码:

function JSONstringifyWithFuncs(obj) {Object.prototype.toJSON = function () {var sobj = {}, i;for (i in this)if (this.hasOwnProperty(i))sobj[i] = typeof this[i] == 'function' ?this[i].toString() : this[i];return sobj;}
}

这样,json里面function的信息也不回丢失。

Class使用的是John Resig的Class,init为构造函数,使用_super可以调用父类方法很方便。

总结

有些好的东西,由于历史原因可能会遭受大量的反对,但这就是我心目中,理想规范方便极简的模块化开发方式,后续发布并支持脚本加载和namespace树,如:

system

system.web

system.web.ui

system.web.ui.control

system.web.ui.control.xx.xxx.xxx.xxx……

求砖和荐。

AMD and CMD are dead之js模块化黑魔法相关推荐

  1. 浅谈js模块化:commons、AMD、CMD、ES6几种模块化的用法及各自的特点

    文章目录 一个页面需要引入多个js文件引发的问题: 模块化的好处: 几种常用的模块化规范 1. commonJs 2. AMD 3. ES6 4.CMD 总结 js模块化是现在比较流行的一种用法,它能 ...

  2. AMD and CMD are dead之KMD.js版本0.0.2发布

    更新 正式从UglifyJS切换至UglifyJS2 增加依赖可视化功能 压缩代码更加方便 统一风格:如main的class名也不能省略 优化了kmdjs管道 修复了无数bug 通过src开启debu ...

  3. AMD and CMD are dead之KMD.js依赖可视化工具发布

    使用 require("MyAapp.DepTree", function (DepTree) {DepTree(({renderTo: "holder",wi ...

  4. JavaScript进阶(十二)JS 模块化编程规范-CommonJS、AMD、CMD、ES6

    文章目录 一.前言 二.AMD-异步模块定义 三.CMD-同步模块定义 四.CommonJS 规范 五.ES6 六.拓展阅读 一.前言 AMD.CMD.CommonJs是ES5中提供的模块化编程方案, ...

  5. javascript模块化之CommonJS、AMD、CMD、UMD、ES6

    javascript模块化之CommonJS.AMD.CMD.UMD.ES6 一.总结 一句话总结: CommonJS是同步加载模块,用在服务端:AMD是异步加载模块,用于浏览器端 1.为什么服务器端 ...

  6. 模块化开发:AMD、CMD、CommonJs和Es6的区别

    什么是AMD.CMD.CommonJs? 他们之间有什么区别? 项目当中都是如何运用的? AMD即Asynchronous Module Definition,是RequireJS在推广过程中对模块定 ...

  7. AMD、CMD、CommonJS、ES6(import/export)

    AMD.CMD.CommonJS.ES6(import/export) AMD.CMD.CommonJS是ES5模块化解决方案 AMD -- 异步模块 Asynchronous Module Defi ...

  8. 浅谈前端JS模块化开发的概念

    引子: 前端开发模块化,这个概念从我接触前端开发就一直看到,但是一直没好好的梳理这其中的概念,直到最近才感觉对这其中的概念是很陌生而熟悉.因此记此梳理里面的一些名词. 模块化: 整个web的发展越来越 ...

  9. js模块化编程之彻底弄懂CommonJS和AMD/CMD!

    为什么80%的码农都做不了架构师?>>>    先回答我:为什么模块很重要? 答:因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块. 但是,这样做有一个前 ...

最新文章

  1. 使用大脑活动反馈的刺激技术自动化治疗脑部疾病
  2. 【Matlab 图像】边缘检测算法及效果演示
  3. Eclipse新建的Maven项目想修改DynamicWebModule,直接去项目目录下修改
  4. JS读取id和name的操作
  5. kafka Failed to send messages after 3 tries 问题解决
  6. Vue - 条件渲染与列表渲染
  7. 云linux搭建 arm开发,arm集成开发环境搭建
  8. jQuery 查找父元素
  9. Android开发笔记(七十七)图片缓存算法
  10. WebKit新特性WebGL
  11. LSET与LREM结合删除list中特定索引的值
  12. DPDK 中文编程指南
  13. 【技术向】如何借助Tushare,学习量化理财(入门)
  14. Autodesk 3DSMax 2016 安装注册说明
  15. 【2】嵌入式TCP/IP协议——————Art-Net处理流程
  16. 本地化差分隐私(Local Differential Privacy)浅析
  17. 你说你懂计算机网络,那这些你都知道吗
  18. 思科模拟器服务器登录显示什么,思科模拟器服务器远程登录
  19. 关于Adobe flash player 本地播放器
  20. Auto CAD:CAD绘图设计以项目为导向,实战案例布局作图运用技巧经验总结之详细攻略

热门文章

  1. SQL Server-流程控制 5,Goto 语句
  2. linux安全问答(1)
  3. PostgreSQL学习笔记(1)
  4. @HostListener 可接收的事件列表
  5. [干货]Kaggle热门 | 用一个框架解决所有机器学习难题
  6. PreparedStatement
  7. EX2010与EX2013共存迁移01-设计及说明
  8. Gartner最新发布十大战略预测
  9. Pjax是什么以及为什么推荐大家用
  10. hibernate中多对多分解成一对多,