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程序,又是两个变量,所以说虽然是闭包,但在一个程序里是同一个变量。最后值得注意需要用函数去取那个变量不能直接导出变量。