你真的懂 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均可用于导出常量.函 ...
随机推荐
- 荷小鱼 x mPaaS | 借助 H5 容器改善 App 白屏、浏览器兼容等问题
随着5G.大数据.人工智能技术的应用,各类传统行业纷纷大力推进数字化转型升级. 而受疫情的影响,教育行业也在大幅加速线上化转型进程,各类在线教育应用也在借助各种力量拓张自己的移动端市场领域. 「荷 ...
- Cisco Catalyst 9800-CL Wireless Controller for Cloud
面向云的思科 Catalyst 9800-CL 无线控制器,专为基于意图的网络全新打造. 版本: C9800-CL-universalk9.17.04.01 (29-Nov-2020) C9800-C ...
- openresty 学习笔记一:环境安装
openresty 学习笔记一:环境安装 openresty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库.第三方模块以及大多数的依赖项.用于方便地搭 ...
- jupyter notebook 默认文件路径修改以及启动
其实这个方法有时候不是特别有效额 方法一: 查了网上好多其他的方法,但是都没用,只好独辟蹊径了. 首先找到anaconda的安装路径,找到jupyter notebook,我的是如下: 发送快捷方式到 ...
- ADAS可行驶区域道路积水反光区域的识别算法
ADAS可行驶区域道路积水反光区域的识别算法 Water logging area reflecting recognition algorithm for ADAS 1. 工程概要 1.1 概述: ...
- 摄像头Camera 标定Calibration原理Theory
摄像头Camera 标定Calibration原理Theory cv2.cameraCalibration Pinhole camera calibration calls camera vision ...
- 激光SLAM与视觉SLAM的特点
激光SLAM与视觉SLAM的特点 目前,SLAM技术被广泛运用于机器人.无人机.无人驾驶.AR.VR等领域,依靠传感器可实现机器的自主定位.建图.路径规划等功能.由于传感器不同,SLAM的实现方式也有 ...
- 多目标跟踪:CVPR2019论文阅读
多目标跟踪:CVPR2019论文阅读 Robust Multi-Modality Multi-Object Tracking 论文链接:https://arxiv.org/abs/1909.0385 ...
- YOLOv3和YOLOv4长篇核心综述(上)
YOLOv3和YOLOv4长篇核心综述(上) 对目标检测算法会经常使用和关注,比如Yolov3.Yolov4算法. 实际项目进行目标检测任务,比如人脸识别.多目标追踪.REID.客流统计等项目.因此目 ...
- NVIDIA Jarvis:一个GPU加速对话人工智能应用的框架
NVIDIA Jarvis:一个GPU加速对话人工智能应用的框架 Introducing NVIDIA Jarvis: A Framework for GPU-Accelerated Conversa ...