如何理解以下这段 Javascript 封装代码?

2016-11-01 17:56:23 +08:00
 jmyz0455

最近尝试研究某 jquery 插件,但是最外层的封装代码看不明白。搜索出来的文章都是各有各说,很难让我从整体上了解整段代码。请教下怎么理解下面这段代码:

01    (function(root, factory) {
02        if (typeof define === 'function' && define.amd) {
03            define('jqname', ['jquery'], factory);
04        } else if (typeof exports === 'object') {
05            module.exports = factory(require('jquery'));
06        } else {
07            factory(root.jQuery);
08        }
09    }(this, function($) {
10        /* code1 */
11    }));

一、 root 我知道是 Window 对象,那请问 01 行的 factory 对应什么对象? console 输出来是整个 /* code1 */ 的部分,网上一搜 "factory" 都是讲工厂模式的,看后对应题目的代码还是想不明白。

二、我知道下面这种 IIFE 写法

(function(){ /* code2 */ }());
(function(){ /* code2 */ })();
但是把题目的代码简化后如下

(function(par1, par2) {
    /* code3 */
}(par3, par4));

那样写的话,后面的 (par3, par4) 就不是分组操作符了吧?那整段题目为什么要那样写、作用又是什么呢? 三、请问 01 行的两个参数是 "谁" 传进去的?(或者说匿名函数的参数是怎么传进去的?立即执行时函数段从哪里获取参数呢?)

四、 02 至 08 行我的理解是,检测网页的 Javascript 是使用何种规范。如果是 AMD ,必然会已声明 define 全局变量,然后 03 行会执行模块加载代码;如果是 CMD ,就会执行 05 行来加载模块。这样理解正确吗?

五、 05 行的 factory(require('jquery')) 看不懂

六、 07 行的 factory(root.jQuery) 看不懂

七、 09 行的 this 是指 Window 对象吗?

问题有点多,请赐教。

2144 次点击
所在节点    JavaScript
9 条回复
chemzqm
2016-11-01 18:06:15 +08:00
UMD 封装,可以支持全局方式加载,以及 AMD 和 CMD 方式加载
https://github.com/umdjs/umd
cheetah
2016-11-01 18:08:16 +08:00
factory 就是

```
function($) {
/* code1 */
}
```

这个匿名函数
wesley
2016-11-01 18:10:34 +08:00
前 3 个问题:
这段代码
(function(par1, par2) {
/* code3 */
}(par3, par4));
写成这种形式你就明白了
function xxx(par1,par2){
.......
}
xxx(par3, par4);
palmers
2016-11-01 18:34:10 +08:00
>
五、 05 行的 factory(require('jquery')) 看不懂

这个是将 jquery 模块化使用支持。

我是参考 Node.js 模块化想的,我想应该不会错的。
beginor
2016-11-01 18:50:38 +08:00
umd,同时适应 amd 和 cjs
des
2016-11-01 19:18:28 +08:00
简单的说下吧,第九、十行是一个包裹函数,期待一个 jq 对象,用来拓展$.fn
第三、五行分别是不同的封装用来获取 jQuery 对象,并注入到 factory 中,也就是前面的包裹函数。
第七行是直接从全局拿 jQuery ,然后注入。
至于第五行的 module.exports 和 require 你去了解一下 AMD/UMD 的写法就清楚了
lijsh
2016-11-01 22:09:38 +08:00
你找个好点的编辑器看清楚代码块开合,首先是匿名函数立即调用的问题,整个代码块大概是这样的形式
(function(root, factory) {
/* 模块导入的逻辑 */
} (this, function($) { /* 模块的实际逻辑 */ }));

这里使用 IIFE 将 this 作为实参传进去作为 root , function($) { /* code1 */ } 这个函数传进去作为 factory (所以你 console 才会输入 code1 ),这个 factory 才是整个插件的实际逻辑。

至于模块导入,也就是那串 if ... else if ... else 的逻辑,分别对应 amd 、 commonjs 和 window 全局的三种格式,最终都是把 function($) { /* code1 */ } 导出成模块。
lijsh
2016-11-01 22:14:33 +08:00
补充一下, function($) { /* code1 */ } 里要传进$,明显是 jQuery 了, amd 、 commonjs 和 window 全局三种规范导入 jQuery 模块的方式也并不相同,因此
if (typeof define === 'function' && define.amd) {
define('jqname', ['jquery'], factory);
} else if (typeof exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(root.jQuery)
}
这一段的大概逻辑是
if 是 amd 模块规范( define 是个函数),使用 amd 模块规范将 jQuery 传给 function($) { /* code1 */ }
else if 是 commonjs 规范( exports 是个已定义的 object ),使用 commonjs 规范将 jQuery 传给 function($) { /* code1 */ }
else 没有模块规范,直接找 window.jQuery 传进去。
ryanzyy
2016-11-02 12:35:17 +08:00
楼上回答地非常详细
补充一句 "从整体上了解整段代码" --> 这段代码的服务对象是你. 让你在任何地方都能使用这个 module. 包括你最终在浏览器里运行的产品以及你的测试代码
ref: http://bob.yexley.net/umd-javascript-that-runs-anywhere/

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/317169

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX