ES6模块加载问题

问题

PM提了个需求:查询广告 接口上送的 PlayRuleId(广告字段)的值改成可配置的,而这个值会在 查询数据字典 接口中返回。

交易流程:调用 查询数据字典 接口,然后将结果存储到 store 里,数据字典文件通过一个 getDictJson 函数获取到处理后的数据字典,在需要使用数据字典的页面 import 数据字典文件对应变量即可。

数据字典文件 newCenterDict.js 如下:

其中 dictTran.js 如下:

由于,查询数据字典查询广告 接口是在同一个vue页面 shopShow.vue,因此我在 shopShow.vue 中 import newCenterDict.js 中的变量时,会导致变量是 [],并且会导致后续路由到的界面(凡是import newCenterDict.js文件中的变量)都获取到 []。

记得阮一峰老师在ES6中对于模块加载有说过:ES6 的 import 原始值变了,import加载的值也会跟着变,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。但是现在遇到的情况好像不是这样,因为阮老师博客验证的是基本类型赋值,于是我写了个 demo 来验证我的一些猜想。

探究

我直接用 vue-cli 搭建了个 vue 工程,然后简单配置了两个路由,分别从 App.vue 路由到 test.vue、anotherTest.vue。
demo 目录如下:

猜想:export 的变量是引用赋值,被引用对象改变,import 的变量会跟着变

验证一

思路:模块 export 一个方法,该方法可以改变模块中变量的引用。

test1.js:

let Obj = {
    key : '1'
};

export var Big_Value = Obj;

export function change_BigValue() {
    Obj.key = '2';
    console.log('test1.js里,change_BigValue调用,Big_Value值为:');
    console.log(Big_Value)
}

test.vue:

<template>
    <div>
        <h1>测试</h1>
        <div @click="back">返回</div>
    </div>
</template>

<script>
import router from '../../router/index';
import { Big_Value, change_BigValue } from '../../test1';

export default {
    created() {
        console.log('test.vue创建时 Big_Value:');
        console.log(Big_Value);
        change_BigValue();

        console.log('test.vue调用 change_BigValue 后 Big_Value:');
        console.log(Big_Value);
    },
    methods: {
        back() {
            router.push('/')
        }
    }
}

</script>

结果:

验证二

思路:模块里通过 setTimeout 在5秒后改变导出的变量值,在引入变量的页面先打印该值,然后在10秒后再打印一次。

test1.js

let Obj = {
    key : '1'
};

export var Big_Value = Obj;

setTimeout(() => {
    Obj.key = '2';
    console.log('test1.js里,在5秒后 Big_Value 变成:');
    console.log(Big_Value);
}, 5000);

anotherTest.vue

<template>
    <div>
        <h1>另一个测试</h1>
        <div @click="back">返回</div>
    </div>

</template>

<script>
    import { Big_Value } from '../../test1';
    import router from '../../router/index';
    export default {
        created() {
            console.log('anotherTest.vue创建时:');
            console.log(Big_Value);
            setTimeout(() => {
                console.log('来自anotherTest,10秒后 Big_Value:');
                console.log(Big_Value);
            }, 10000);
        },
        methods: {
            back() {
                router.push('/')
            }
        }
    }
</script>

结果:

验证三

还有一种引用类型-函数。虽然在 Js 中,函数也是对象。但是我遇到的问题,就是通过函数取值的。所以在此需要验证一下。

test1.js:

console.warn('test1.js执行');

let a = "1"
function getValue() {
    setTimeout(() => {
        a = '2';
        console.log('5秒后 getValue 将 a 变成:' + a);
        console.log('此时 Big_Value:' + Big_Value);
    }, 5000);

    return a;
}

export var Big_Value = getValue();
console.log('test1.js刚执行时,Big_Value:' + Big_Value);

test.vue:

<template>
    <div>
        <h1>测试</h1>
        <div @click="back">返回</div>
    </div>
</template>

<script>
    import router from '../../router/index';
    import { Big_Value } from '../../test1';

    export default {
        created() {
            console.log('test.vue创建时 Big_Value:' + Big_Value);

            setTimeout(() => {
                console.log('来自test.vue,10秒后 Big_Value:' + Big_Value);
            }, 10000);
        },
        methods: {
            back() {
                router.push('/')
            }
        }
    }

</script>

anotherTest.vue

<template>
    <div>
        <h1>另一个测试</h1>
        <div @click="back">返回</div>
    </div>

</template>

<script>
    import { Big_Value } from '../../test1';
    import router from '../../router/index';
    export default {
        created() {
            console.log('anotherTest.vue创建时:' + Big_Value);
        },
        methods: {
            back() {
                router.push('/')
            }
        }
    }
</script>

结果:

结论

综上:ES6 的模块加载,import 加载的值,如果是通过调用函数得到的返回值,该函数若内部返回值发生改变,加载的值并不会发生改变(并不会重新调用函数去获取返回值)。