export default Aexport { A as default } 乍一看是一样的,但是里面有一些细微的区别比较容易留坑。本文介绍两种写法的不同之处。

import 语句导入的是引用,不是值

有导出就必然有导入,我们先明确下 import 语句的工作原理。

import { A } from './module.js';

显而易见,在上面的代码中,A./module.js 中的 A 是相同的。再看这段代码:

const module = await import('./module.js');
const { A: destructuredA } = await import('./module.js');

在这段代码中,module.AA 是相同的,但是因为 destructuredA 是结构赋值,因此就有一些不同了。

我们来看下 ./module.js

// module.js
export let A = 'initial'; setTimeout(() => {
A = 'changed';
}, 500);

导入 ./module.js 的代码为 ./main.js

// main.js
import { A as importedA } from './module.js';
const module = await import('./module.js');
let { A } = await import('./module.js'); setTimeout(() => {
console.log(importedA); // "changed"
console.log(module.A); // "changed"
console.log(A); // "initial"
}, 1000);

import 语句导入的是引用,也就是说,当 ./module.jsA 的值发生变化的时候,./main.js 中也会跟着变化。解构赋值获得的 A 不会变化是因为解构过程中是使用的值赋值给了新变量,而不是引用。

值得注意的是,静态语句 import { A } ... 虽然看着像解构赋值,实际上与解构赋值并不相同。

小结一下:

// 以下代码获得是引用
import { A } from './module.js';
import { A as otherName } from './module.js';
import * as module from './module.js';
const module = await import('./module.js');
// 以下代码获得的是值
let { A } = await import('./module.js');

export default

我们修改下 ./module.js

// module.js
let A = 'initial'; export { A };
export default A; setTimeout(() => {
A = 'changed';
}, 500);

同时也修改 ./main.js

// main.js
import { A, default as defaultA } from './module.js';
import anotherDefaultA from './module.js'; setTimeout(() => {
console.log(A); // "changed"
console.log(defaultA); // "initial"
console.log(anotherDefaultA); // "initial"
}, 1000);

输出结果是 "initial",为什么呢?

我们知道,我们可以直接 export default 'hello'; 但是却不能 export { 'hello' as A }。规范在这两种语法上有一点不同。export default 后面的将会被作为表达式对待。因此我们可以 export default 'hello';, 甚至可以 export default 1 + 2;。因此,在 export default A 中,A 是作为表达式语句使用的,因此使用的是 A 的值。因此,当 A 的值在 setTimeout 中被改变的时候,export default 出去的值并没有变化。

小结一下:

// 引用
import { A } from './module.js';
import { A as otherName } from './module.js';
import * as module from './module.js';
const module = await import('./module.js');
// 值
let { A } = await import('./module.js'); // 导出引用
export { A };
export { A as otherName };
// 导出值
export default A;
export default 'hello!';

export { A as default }

export {} 导出的始终是一个引用,因此:

// module.js
let A = 'initial'; export { A, A as default }; setTimeout(() => {
A = 'changed';
}, 500);

同样,在先前的 ./main.js 中:

// main.js
import { A, default as defaultA } from './module.js';
import anotherDefaultA from './module.js'; setTimeout(() => {
console.log(A); // "changed"
console.log(defaultA); // "changed"
console.log(anotherDefaultA); // "changed"
}, 1000);

小结下:

// 导入引用
import { A } from './module.js';
import { A as otherName } from './module.js';
import * as module from './module.js';
const module = await import('./module.js');
// 导入值
let { A } = await import('./module.js'); // 导出引用
export { A };
export { A as otherName };
export { A as default };
// 导出值
export default A;
export default 'hello!';

export default function

虽然,前面说过 export default 后面的会被作为表达式使用。但是也有一些例外:

// module.js
export default function A() {} setTimeout(() => {
A = 'changed';
}, 500);
// main.js
import A from './module.js'; setTimeout(() => {
console.log(A); // "changed"
}, 1000);

输出 "changed",因为 export default function 有其特殊的语法,在这个语法中,函数是作为引用传递的。

我们稍微做一下修改:

// module.js
function A() {} export default A; setTimeout(() => {
A = 'changed';
}, 500);

此时控制台输出 ƒ A() {}export 语句不再符合 export default function 语法形式,A 便使用了值传递。

不仅仅 export default functionexport default class 也是同样的表现。

为什么呢?

原因与这些语句当被用作表达式时的表现有关。

function someFunction() {}
class SomeClass {} console.log(typeof someFunction); // "function"
console.log(typeof SomeClass); // "function"

如果我们将他们变成表达式:

(function someFunction() {});
(class SomeClass {}); console.log(typeof someFunction); // "undefined"
console.log(typeof SomeClass); // "undefined"

functionclass 语句会在作用域/块中创建标识符,而 functionclass 语句却不会,尽管他们的函数名和类名可以被使用。

因此,下面代码中:

export default function someFunction() {}
console.log(typeof someFunction); // "function"

如果不进行特殊处理的话,输出的将会是 "undefined"

小结如下:

// 导入引用
import { A } from './module.js';
import { A as otherName } from './module.js';
import * as module from './module.js';
const module = await import('./module.js');
// 导入值
let { A } = await import('./module.js'); // 导出引用
export { A };
export { A as otherName };
export { A as default };
export default function A() {}
// 导出值
export default A;
export default 'hello!';

在早些时候,模块中的默认导出是这样的 export default = A,这样看来,A 被当做表达式会更明显一些。

你真的懂 export default 吗?的更多相关文章

  1. module.exports,exports,export和export default,import与require区别与联系

    还在为module.exports.exports.export和export default,import和require区别与联系发愁吗,这一篇基本就够了! 一.首先搞清楚一个基本问题: modu ...

  2. [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?

    你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...

  3. babel6 的 export default bug

    把export default  变成 module.exports 就行了

  4. 【转】was mutated while being enumerated 你是不是以为你真的懂For...in... ??

    原文网址:http://www.jianshu.com/p/ad80d9443a92 支持原创,如需转载, 请注明出处你是不是以为你真的懂For...in... ??哈哈哈哈, 我也碰到了这个报错 . ...

  5. javascript的语法作用域你真的懂了吗

    原文:javascript的语法作用域你真的懂了吗 有段时间没有更新了,思绪一下子有点转不过来.正应了一句古话“一天不读书,无人看得出:一周不读书,开始会爆粗:一月不读书,智商输给猪.”.再加上周五晚 ...

  6. 你真的懂ajax吗?

    前言 总括: 本文讲解了ajax的历史,工作原理以及优缺点,对XMLHttpRequest对象进行了详细的讲解,并使用原生js实现了一个ajax对象以方便日常开始使用. damonare的ajax库: ...

  7. module.exports与exports,export和export default

    还在为module.exports.exports.export和export default,import和require区别与联系发愁吗,这一篇基本就够了! 一.首先搞清楚一个基本问题: modu ...

  8. module.exports,exports,export和export default,import与require区别与联系【原创】

    还在为module.exports.exports.export和export default,import和require区别与联系发愁吗,这一篇基本就够了! 一.首先搞清楚一个基本问题: modu ...

  9. JavaScript ES6中export及export default的区别

    相信很多人都使用过export.export default.import,然而它们到底有什么区别呢? 在JavaScript ES6中,export与export default均可用于导出常量.函 ...

随机推荐

  1. Ansible_使用文件模块将修改文件复制到受管主机

    一.描述常用文件模块 1.常用文件模块 模块名称 模块说明 blockinfile 插入.更新或删除由可自定义标记线包围的多行文本块 copy 将文件从本地或远程计算机复制到受管主机上的某个位置.类似 ...

  2. Redis 快速集群环境搭建

    环境 Linux :centos 7 redis:redis-5.0.9 Redis 集群环境搭建步骤 早期 redis 版本集群环境搭建需要安装 ruby 运行环境,搭建步骤比较繁琐: redis ...

  3. 第六章 XaaS和IT服务标准

    从云计算(Cloud Computing)谈起 云计算是一种按使用量付费的模式,这种模式提供可用的.便捷的.按需的网络访问,进入可配置的计算资源共享池(资源包括网络,服务器,存储,应用软件,服务),这 ...

  4. 第6讲 | 交换机与VLAN:办公室太复杂,我要回学校

    第6讲 | 交换机与VLAN:办公室太复杂,我要回学校 拓扑结构是怎么形成的? 一个交换机肯定不够用,需要多台交换机,交换机之间连接起来,就形成一个稍微复杂的拓扑结构. 如何解决常见的环路问题? 包转 ...

  5. 多表联合查询 - 基于注解SQL

    作者:汤圆 个人博客:javalover.cc 前言 背景:Spring Boot + MybatisPlus 用MybatisPlus就是为了不写SQL,用起来方便: 但是如果需要多表联合查询,还是 ...

  6. Python小白的数学建模课-A1.国赛赛题类型分析

    分析赛题类型,才能有的放矢. 评论区留下邮箱地址,送你国奖论文分析 『Python小白的数学建模课 @ Youcans』 带你从数模小白成为国赛达人. 1. 数模竞赛国赛 A题类型分析 年份 题目 要 ...

  7. 人工智能AI智能加速卡技术

    人工智能AI智能加速卡技术 一. 可编程AI加速卡 1. 概述: 这款可编程AI加速器卡具备 FPGA 加速的强大性能和多功能性,可部署AI加速器IP(WNN/GNN,直接加速卷积神经网络,直接运行常 ...

  8. java8 函数式编程接口

    java8 函数式接口java.util.function.* @param T 入参类型 @param R 出参类型 1. Function <T,R> 例: Function<I ...

  9. 前端 JS 之 AJAX 简介及使用

    概述 AJAX 是一个缩写,它的全名是 Asynchronous JavaScript and XML,意思就是异步 JavaScript 和 XML,即用JavaScript执行异步网络请求. AJ ...

  10. 题解 P6622 [省选联考 2020 A/B 卷] 信号传递

    洛谷 P6622 [省选联考 2020 A/B 卷] 信号传递 题解 某次模拟赛的T2,考场上懒得想正解 (其实是不会QAQ), 打了个暴力就骗了\(30pts\) 就火速溜了,参考了一下某位强者的题 ...