ES6模块 - 为什么命名const导出不是只读

时间:2017-08-22 12:16:07

标签: javascript ecmascript-6 babeljs es6-modules

我一直在reading about ES modules进行实验并偶然发现了一个我无法解释的案例:

// settings.js
export const FOO = 42;
export const BAR= 5;

// main1.js
import * as settings from './settings';
settings.FOO = 1;

//main2.js
import {FOO, BAR} from './settings'
FOO = 1;

main1.js我可以通过const变量覆盖settings值,但在main2.js我不能(正如预期的那样)。

(理论上)问题是为什么在第一种情况下可以覆盖const值?创建“只读视图”是否只是在常规对象上创建属性并破坏原始结构?

实际问题是从模块返回常量集合(或只读属性)的最有效方法是什么?我的想法是:

// settings.js
export default Object.freeze({
  FOO: 42,
  BAR: 5
});

有什么想法吗?

编辑:我正在使用巴贝尔。

2 个答案:

答案 0 :(得分:8)

另一个答案是错误的。

  

(理论上)问题是为什么在第一种情况下可以覆盖const值?

这实际上完全独立于const。使用ES6模块语法,不允许从模块外部重新分配模块的导出值。 export let FOO;export var FOO;也是如此。代码内部模块是唯一允许更改导出的东西。

在技术上做settings.FOO = 1应该抛出异常,但大多数编译器目前都没有处理这个特殊的边缘情况。

举个例子,你可以做到

export var FOO;

export function setFoo(value){
  FOO = value;
}

并且鉴于此,const变得有用的原因,因为它与任何其他普通的JS代码相同。 FOO = value如果被声明为export const FOO则会失败,所以如果你的模块导出了一堆常量,那么执行export const FOO = 1, FOO2 = 2;是导出常量的好方法,它只是那个巴别塔实际上并没有使它们永不变化。

答案 1 :(得分:1)

在此代码中

import * as settings from './settings';
settings.FOO = 1;

在上面的代码中,您不是直接分配常量变量,而是分配settings中的克隆副本。

import * as settings from './settings';
         ^^^^^^^^^^^^
settings.FOO = 1;

但在下一个代码中并非如此

import {FOO, BAR} from './settings'
FOO = 1;

此处FOOBAR是常量,您无法分配给它。