资讯专栏INFORMATION COLUMN

js手札--关于AMD的简单分析

frank_fun / 1005人阅读

摘要:废话真多,是的哈而要说清和的二三事,又不是件容易的事,简单理解,和指向同一内存区域。而对于当前模块来说是外部的模块。参考关于和的区别和的区别这篇文章很不赖。

AMD中define常见的形式
define("alpha" ,["require", "exports", "module"], function(require, exports, module) {
  var foo = require("foo");
  module.exports = exports = function() {
    foo.doSomething();
  }
});

参数

第一个是要定义的模块名字(id)
第二个是要用到的模块名,其实更专业点讲是定义的这个模块所依赖的模块名称
第三个回调函数,是要定义模块内容

分析define的回调函数

分析方法:替换部分代码进行分析

先来把回调中的require,exports,module替换了看看。

1.替换require
function callback(exports, module) {
  // 假设foo是最简单的对象,把require("foo")换成最简答的对象看看
  var foo = {
    "doSomething": function() {}
  };

  module.exports = exports = function() {
    foo.doSomething();
  }
}

那么其实已经不难看出,require其实就相当于是个查询函数吧,我给他传个对象名,它就能给我一个具体的对象。

var require = function(name) {
  var modules = {"foo": {"doSomething": function() {}}};
  return modules[name] || {};
}

那么整个代码可以换成

var require = function(name) {
  var modules = {"foo": {"doSomething": function() {}}};
  return modules[name] || {};
}

function callback(exports, module) {
  var foo = require("foo");
  module.exports = exports = function() {
    foo.doSomething();
  }
}

看起来好像有点道理哦,等会儿,等会儿,这里的modules又从哪儿冒出来的,哈哈哈,被发现了,别急慢慢来

2. 替换exports和module.exports

在替换之前,先来了解下exports和module.exports这两货是干啥的,而要了解他们先来看看模块是啥。

其实模块么,简单来说就是一个高级别的function,输入,处理,输出。至于为啥js的模块化为啥这么困难,这个问题不是三言两语就能解释清楚的,就不展开了(其实真实情况是,我也不清楚,哈哈哈)

既然模块要做输出,那么输出什么东西总要知道吧,而module.exports的作用就是这个,存储模块输出的内容。

也就是说,这个模块中要给外部使用的东西全放在module.exports里头了。废话真多,是的哈- -.

而要说清exports和module.exports的二三事,又不是件容易的事,简单理解,exports和module.exports指向同一内存区域。有兴趣可以看看exports 和 module.exports 的区别。

那来改造一下,把module.exports,exports也提炼出来看看

var require = function(name) {
  var modules = {"foo": {"doSomething": function() {}}};
  return modules[name] || {};
}

var module = {};
var module.exports = exports = {};

function callback() {
  var foo = require("foo");

  module.exports = exports = function() {
    foo.doSomething();
  }
}
define的推测
// 这里的id相当于模块名,deps就是需要依赖的模块名称列表
define = function(id , deps, callback) {
  callback(require, exports, module);
};

晕,那require,exports,module跑哪儿溜达去了?加上去看看

define = function(id , deps, callback) {
  
  var require = function(name) {
    var modules = {"foo": {"doSomething": function() {}}};
    return modules[name] || {};
  }

  var module = {};
  var module.exports = exports = {};

  callback(require, exports, module);
};

看上去挺有道理的么,那么modules这玩意儿到底是哪儿冒出来的呢。

可以看出来modules 里面存放着的是foo模块的内容,那这些内容是怎么来的呢?通过foo的module.exports提供的啊。那么modules里面其实放的是,foo的module.exports。

而foo对于当前模块来说是外部的模块。而我想调用外面的东西,只有两种办法,要么传参数,要么通过全局变量(不过或许大神还有其他方案,我就只晓得这两种了)。define里面有的参数没有一个是存放module.exports的。那么答案呼之欲出了,modules是全局变量。

modules = {};
function load(id, exports) {
  (modules || (modules = {}))[id] = exports;
}

再来看看完整的代码,变成啥样了

modules = {};
function load(name, exports) {
  (modules || (modules = {}))[name] = exports;
}

define = function(id, deps, callback) {
  
  var require = function(name) {
    return modules[name] || {};
  }

  var module = {};
  var module.exports = exports = {};

  callback(require, exports, module);

  load(id, module.exports);
};

到现在差不多已经成型了,那么这里的require, exports, module都是外来的模块吧bingo,其实callback里的模块都是根据deps来的,去掉require, exports, module

modules = {};
function load(name, exports) {
  (modules || (modules = {}))[name] = exports;
}

define = function(id, deps, callback) {
  
  // 相当于
  // var module = {};
  // var module.exports = {};
  var module = modules["module"];
  
  // 相当于
  //var require = function(name) {
  //  return modules[name] || {};
  //}
  var require = modules["require"];

  var args = deps.map(require);

  callback.apply(null, args);

  load(id, module.exports);
};
来看define的另一种形式
define("alpha" ,["foo"], function(foo) {
  return function() {
    foo.doSomething();
  }
});

咦,精简了不少诶。没有exports了诶,会返回了么

modules = {};
function load(name, exports) {
  (modules || (modules = {}))[name] = exports;
}

define = function(id, deps, callback) {
  
  var module = modules["module"];
  
  var require = modules["require"];

  var args = deps.map(require);

  var exports = callback.apply(null, args);

  load(id, exports || module.exports);
};

OK,先告一段落了,累死我丫了。在慢慢优化吧,唉。

参考(关于exports 和 module.exports 的区别)

exports 和 module.exports 的区别这篇文章很不赖。

人家大神已经说得非常好了。我在了浅薄的打个比方,我有个文件夹叫module.exports,然后我创建了一个超链接叫exports,那我在任何一个里面操作最终都会反应到另一个里,但如果我把超链接exports删了把它的指向地址改了,并不会影响真正的文件夹module.exports。

而有很多人明明已经改了超链接exports的指向地址(如:exports = 123;),再在超链接里面做了很多操作(如:exports.hello = 456;),那都不会对真正的文件夹module.exports起到任何作用(你是见不到module.exports.hello === 456的)。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79529.html

相关文章

  • 前端临床手札——webpack构建逐步解构(上)

    摘要:前言由于博主最近又闲下来了,之前觉得的官方文档比较难啃一直放到现在。文章会逐步分析每个处理的用意当然是博主自己的理解,不足之处欢迎指出沟通交流。后续将会补上构建生产的配置分析,案例参考。前端临床手札构建逐步解构下 前言 由于博主最近又闲下来了,之前觉得webpack的官方文档比较难啃一直放到现在。细心阅读多个webpack配置案例后觉得还是得自己写个手脚架,当然这个案例是基于vue的,...

    lowett 评论0 收藏0
  • js手札--关于事件冒泡与事件捕获

    摘要:一冒泡和捕获事件执行子元素在执行某个事件的前后,会引起上层元素触发相同事件。三补充关于和这两个其实和捕获与冒泡一点关系都没有,是用来阻止事件的默认行为的。 一、冒泡和捕获 事件执行:子元素在执行某个事件的前后,会引起上层元素触发相同事件。例:我点击了div,那么不光div会执行click事件,上层的body和html等等也会执行click。 冒泡与捕获解决了:事件执行顺序由谁开始,由谁...

    lentoo 评论0 收藏0
  • 前端临床手札——单元测试

    摘要:感觉不能这样下去就学写一下单元测试,等他更新代码我都跑一遍确认一下,这样工作安心多了。具体执行的测试用例实现代码。测试工具断言库测试驱动开发及测试框架入门学习 最近博主工作是和另一枚后端合作,但是经常发现他写的接口出错,苦逼连连。感觉不能这样下去就学写一下单元测试,等他更新代码我都跑一遍确认一下,这样工作安心多了。 经过博主一番查找,貌似被推荐比较多的有mocha和chai,下面记录简...

    kid143 评论0 收藏0
  • 前端临床手札——单元测试

    摘要:感觉不能这样下去就学写一下单元测试,等他更新代码我都跑一遍确认一下,这样工作安心多了。具体执行的测试用例实现代码。测试工具断言库测试驱动开发及测试框架入门学习 最近博主工作是和另一枚后端合作,但是经常发现他写的接口出错,苦逼连连。感觉不能这样下去就学写一下单元测试,等他更新代码我都跑一遍确认一下,这样工作安心多了。 经过博主一番查找,貌似被推荐比较多的有mocha和chai,下面记录简...

    godlong_X 评论0 收藏0
  • 前端临床手札——在微信播放视频那些事

    摘要:然而我真的太天真,微信浏览器怎样会让你这样好过问题集中于自动播放视频这块,需求很简单自动播放全屏不显示工具条自动播放一步步来,自动播放这个问题在十分肯定默认是不支持的,必须基于用户操作下才能加载视频。至于在微信下和一个样。 某天收到旧同事的信息说希望我帮手做一下一个简单的H5,然后我看了看的确很简单: 就是图片滚动到最后自动播放视频,播完显示个按钮交互。 然而我真的太天真,微信浏览器怎...

    _Zhao 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<