你真的懂 export default 吗?
export default A和export { 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.A 与 A 是相同的,但是因为 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.js 中 A 的值发生变化的时候,./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 function,export 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"
function 和 class 语句会在作用域/块中创建标识符,而 function 和 class 语句却不会,尽管他们的函数名和类名可以被使用。
因此,下面代码中:
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 吗?的更多相关文章
- module.exports,exports,export和export default,import与require区别与联系
还在为module.exports.exports.export和export default,import和require区别与联系发愁吗,这一篇基本就够了! 一.首先搞清楚一个基本问题: modu ...
- [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?
你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...
- babel6 的 export default bug
把export default 变成 module.exports 就行了
- 【转】was mutated while being enumerated 你是不是以为你真的懂For...in... ??
原文网址:http://www.jianshu.com/p/ad80d9443a92 支持原创,如需转载, 请注明出处你是不是以为你真的懂For...in... ??哈哈哈哈, 我也碰到了这个报错 . ...
- javascript的语法作用域你真的懂了吗
原文:javascript的语法作用域你真的懂了吗 有段时间没有更新了,思绪一下子有点转不过来.正应了一句古话“一天不读书,无人看得出:一周不读书,开始会爆粗:一月不读书,智商输给猪.”.再加上周五晚 ...
- 你真的懂ajax吗?
前言 总括: 本文讲解了ajax的历史,工作原理以及优缺点,对XMLHttpRequest对象进行了详细的讲解,并使用原生js实现了一个ajax对象以方便日常开始使用. damonare的ajax库: ...
- module.exports与exports,export和export default
还在为module.exports.exports.export和export default,import和require区别与联系发愁吗,这一篇基本就够了! 一.首先搞清楚一个基本问题: modu ...
- module.exports,exports,export和export default,import与require区别与联系【原创】
还在为module.exports.exports.export和export default,import和require区别与联系发愁吗,这一篇基本就够了! 一.首先搞清楚一个基本问题: modu ...
- JavaScript ES6中export及export default的区别
相信很多人都使用过export.export default.import,然而它们到底有什么区别呢? 在JavaScript ES6中,export与export default均可用于导出常量.函 ...
随机推荐
- shell脚本编写习惯
前言:在公众号看一篇比较不错的shell脚本文章,自己学习同时,加一些例子分享下,哪里做得不好,请多多指教哈一.在脚本写注释 1 #脚本的参数 2 #脚本的用途 3 #脚本的注意事项 4 #脚本的写作 ...
- 2021.5.23 noip模拟2(排序|划艇|放棋子)
今天比昨天更惨,惨炸了 看到T1不会,跳!!! T2不会,再跳!!!! T3不会,后面没题了:::: 无奈无奈,重新看T1,然鹅时间已经过去了一个小时 然而我一想不出题来就抱着水瓶子喝水,然后跑厕所, ...
- TVM性能评估分析(三)
TVM性能评估分析(三) Figure 1. TVM's WebGPU backend close to native GPU performance when deploying models to ...
- h264和h265多维度区别
h264和h265多维度区别 1. 概述 h265旨在在有限带宽下传输更高质量的网络视频,仅需原先的一半带宽即可播放相同质量的视频,很多朋友不知道h264和h265如何区别,下面让我们一起来了解一下 ...
- 部署通用基础设施, 满足顶级 SLA 要求
部署通用基础设施, 满足顶级 SLA 要求 Telefónica 使用基于英特尔 至强 可扩展处理器和英特尔 傲腾 数据中心级固态盘 的 VMware 虚拟存储区域网络 (vSAN)* 架构,完成对高 ...
- 教你三种jQuery框架实现元素显示及隐藏动画方式
摘要:在jQuery框架中对元素对象进行显示和隐藏有三种方式,分别是"默认方式显示和隐藏"."滑动方式显示和隐藏"."淡入淡出显示和隐藏". ...
- 解决redis集群版本不一致导致RDB同步失败的问题
某天,运维反馈某两个机房的出口流量和入口流量过大,并且持续了好一段时间. 再仔细排查后发现是 redis 集群的几台服流量问题,于是开始查日志. 在日志中发现出现大量的 Can't handle RD ...
- Qt中的内存回收机制
Qt中的内存回收机制 在Qt中创建对象的时候会提供一个 Parent对象指针(可以查看类的构造函数),下面来解释这个parent到底是干什么的. QObject是以对象树的形式组织起来的.当你创建一个 ...
- jmeter--文件上传和下载
文件下载 文件下载的method一般是get.本例中导出excel文件. 下载文件如果要求下载到本地,需要另写脚本.采用jsr223或者beashell PostProcessor都可以. 代码如下: ...
- Visual Studio 2022 Preview 1 和.NET 6 Preview 5 正式发布
具有里程碑意义的Visual Studio 2022 Preview 1正式发布,重点是64位,而没有增加新功能,并且同时也发布了.NET 6 Preview 5. https://devblogs. ...