commonjs和ES6及requirejs模块循环引用

Commonjs模块循环引用

commonjs是同步模块加载方式,因此其加载完成后才能执行下面的动作,require第一次加载完该脚本,就会在内存中生成一个对象,类似以:

{
  id: '...',
  exports: { ... },
  loaded: true,
  ...
}

接着运行脚本,从别处引用此模块时,可以引用其exports出来的内容。当模块第二次引用时不会去重复加载,而是执行上次缓存的。

若出现循环引用,就只执行已经输出的(exports)部分,其他的未导出的不用管。

例如a.js和b.js相互引用:
a.js内容为:

exports.done = false;

var b = require('./b.js');

exports.hello = false;

console.log(`在a中b.done的值为:`+b.done);

exports.done = true;

b.js内容为:

exports.done = false;

var a = require('./a.js');

console.log(`在b中a.done的值为:`+a.done);
console.log(`在b中a.hello的值为:`+a.hello);

exports.done = true;

在main.js引用a和b

var a = require('./a.js');
var b = require('./b.js');
console.log(a.done,b.done,b.hello);

var a1 = require('./a.js');
var b1 = require('./b.js');
console.log(a1.done,b1.done,b.hello);

解释:
在a.js中,第一行,导出其done值为false,第二行引用b.js,此时进入b.js中,第一行导出其done值为false,第二行引用a.js,此时进入a.js中,而a.js只执行了两行,只输出了一个值即done为false;所以b.js而 第二行的a只能引用到done值,hello值为undefined。所以b.js输出

在b中a.done的值为:false
在b中a.hello的值为:undefined

b.js执行完成后,其done值为true,然后继续a.js第三行,第四行输出:

在a中b.done的值为:true

此时a中done为true,hello为false,而b.js只能引用a中done的值。
所以console.log(a.done,b.done,b.hello);这行输出:true true undefined,而再次引用a和b时,不会再次执行。所以:

var a1 = require('./a.js');
var b1 = require('./b.js');
console.log(a1.done,b1.done,b.hello);

只会输出:true true undefined

若将a.js变成:

exports.done = false;

setTimeout(function () {
    exports.done = 'anotherDone';
},5000);

var b = require('./b.js');
exports.hello = false;
console.log(`在a中b.done的值为:`+b.done);
exports.done = true;

main.js变成:

var a = require('./a.js');
var b = require('./b.js');
console.log(a.done,b.done,b.hello);

var a1 = require('./a.js');
var b1 = require('./b.js');

setTimeout(function () {
    console.log(a1.done,b1.done,b.hello);
},6000);

输出为:

在b中a.done的值为:false
在b中a.hello的值为:undefined
在a中b.done的值为:true
true true undefined
anotherDone true undefined

最后一行输出a1.done为anotherDone因为exports在内存中是一个对象形成存在的,a1中存储的是对他的引用,所以,a.js改变done后能通过a1体现出来。

ES6 import模块循环引用

ES6中对模块的引用不像commonjs中那样必须执行require进来的模块,而只是保存一个模块的引用而已,因此,即使是循环引用也不会出错。

even.js

import { odd } from './odd'
export var counter = 0;
export function even(n) {
    counter++;
    return n === 0 || odd(n - 1);
}
export function even2() {
   console.log(1234);
}

odd.js

import { even,  even2 } from './even';
export function odd(n) {
    even2();
    return n != 0 && even(n - 1);
}

main.js

require('babel-core/register');
var even = require('./even');
even.even(6);
console.log(even.counter);

运行main.js输出:

1234
1234
1234
4

AMD-RequireJs

requirejs中出现循环引用时,可将引用的模块用局部require进行包裹以避免错误出现:

a.js

define(['require'],function (require) {
    console.log('this is in a ');
    var b = require(['b'],function () {
        console.log('in a b.name:'+b.name);
    });
    function af() {
        console.log('this is af')
    }
    return {
        name:'aname',
        af:af
    };
});

b.js

define(['require'],function (require) {
    console.log('this is in b ');
    var a = require(['a'],function () {
        console.log('in b a.name:'+a.name);
    });
    function bf() {
        console.log('this is bf')
    }
    return {
        name:'bname',
        bf:bf
    };
});

main.js

require(['a'],function (a) {
   a.af();
});

输出:

this is in a 
this is af
this is in b 
in a b.name:localRequire
in b a.name:localRequire

你可能感兴趣的:(javascript)