Contents

好久都没有写博客了,因为暑假要学车,好吧是因为我懒了,不过项目做的还可以,玩了很多新花样,不过我觉得还是要把基础打好,所以一直都想好好再看看犀牛书,可是都不能静下心来,好吧废话不多说,直接来说今天的主要内容,模块化,任何一个大型语言都要模块化不然后期维护会很难,那我今天要说的是什么了,是模块化中的一些细节,有细节就要有应用场景。
这是我做的一个学校教务网的爬虫
后端是用node写的,然后服务器部分是用express,爬虫是我自己写的,当然我就想把爬虫那一部分封装,但是我遇到一个问题,因为教务网老是瘫痪,因为我的爬虫在是定时爬教务网的,有时候爬不到,然后我就在那个模块里设置了一个 count的变量去记录重试的次数,如果超过10次,一个小时之后再试,没有直接爬到,当然这个如果全部卸载一个文件中当然没有问题,但是分开写,我就产生了疑问。这里当 export的是那个count是引用还是拷贝的固定值,然后我记得我之前在阮老师的ES6的教程好象有对比commonJS模块和ES6模块的异同其中好像有答案。
ES模块化实质

ES6模块加载的机制,与CommonJS模块完全不同。CommonJS模块输出的是一个值的拷贝,而ES6模块输出的是值的引用。

那我不禁有疑问了,node使用的是commonjs,那我的这个count不是不会动态变化,看到阮老师的例子好像真的是这样:

CommonJS模块输出的是被输出值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。请看下面这个模块文件lib.js的例子。

1
2
3
4
5
6
7
8
9
// lib.js
var counter = 3;
function incCounter() {
counter++;
}
module.exports = {
counter: counter,
incCounter: incCounter,
};

上面代码输出内部变量counter和改写这个变量的内部方法incCounter。然后,在main.js里面加载这个模块。

1
2
3
4
5
6
// main.js
var mod = require('./lib');
console.log(mod.counter); // 3
mod.incCounter();
console.log(mod.counter); // 3

我自己运行一遍没有错,我觉得肯定不能像我那么写,那我该怎么写了,问题来了。
但是后来我发现像我这么写count的值竟然会变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//lib.js
var count=0;
module.exports=exports={
add:function(){
count++;
},
get:function(){
return count;
}
}
//main.js
var mod=require('./lib');
console.log(mod.get());//0
mod.add();
console.log(mod.get()); // 1

于是我产生了疑问,后来我继续看阮老师的指南我明白了,commonjs相当于创建了一个类似闭包的一样的,导出模块变量其实是一个拷贝,但是实际上函数返回的是一个引用。
于是我写了一个强化版证明我的想法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//lib.js
var count=0;
module.exports=exports={
add:function(){
count++;
},
ifGet:function(){
if(count==0) return 0;
else return 'else';
}
}
//mian.js
var mod=require('./lib');
console.log(mod.ifGet());//0
mod.add();
console.log(mod.ifGet()); // else

然后对比ES6的模块加载实质,是完全静态的只是单纯的返回引用,会更快,在编译的时候就能检查出来错误。
然后我又写了一个来验证我另外一个想法的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//lib.js
var count=0;
module.exports=exports={
add:function(){
count++;
},
ifGet:function(){
if(count==0) return 0;
else return count;
}
}
//test2.js
var mod=require('./lib');
function pp(){
return mod.ifGet();
}
function pp2(){
mod.add();
}
module.exports=exports=pp2;
//test3.js
var mod=require('./lib');
mod.add();
function pp(){
return mod.ifGet();
}
module.exports=exports=pp;
//test.js
var mod=require('./test3');
var mod2=require('./test2')
console.log(mod()); //1
mod2();
console.log(mod()); //2

按照我的理解两次mod打印出来的值是一样,因为test2引用和test3引用是两个作用域事实上不是这样,他们共享的是一个变量,但是如果真正的运行两个node程序,又是两个变量,所以说虽然是闭包,但在一个程序里是同一个变量。最后值得注意需要用函数去取那个变量不能直接导出变量。

Contents