剖析 JavaScript 导入语法
打个招呼!
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
注:这是我之前关于解构赋值文章的后续。导入语法大量使用了解构赋值,这对于新手来说可能会非常令人困惑。如果觉得这篇文章难以理解,建议先阅读我的另一篇文章!
我们来聊聊如何在 Node 项目中导入依赖项。随着项目变得越来越复杂,你不可避免地会遇到类似这样的语法:
import React, { useState, useEffect } from 'react';
import { Link } from 'gatsby';
import Button from '@material-ui/core/Button';
import moment from 'moment';
import { Layout } from '../components';
乍一看,这很简单。我们导入一些代码片段,准备在 React 组件中使用。不过,正如你可能已经猜到的,我之所以选择这四行代码,是因为每一行都独一无二。事实上,在我作为一名正在成长的 Node/React 开发者的道路上,我发现了把这四行代码全部搞砸的方法。
你肯定也会把事情搞砸,但这完全没关系!现在,我就是来帮忙的。
我们将按复杂程度逐一查看这些内容,我会尽力解释到底发生了什么,以及我在工作中思考导入问题的方式。
简单的导入语法——最简单的情况
import moment from 'moment';
如果你用过 .Net 语言、Python、Ruby 或其他任何一种编程语言,这应该是你的第二天性。我在这里特别提一下,是因为我们当中有些人可能以前从未见过这种情况。
这里发生了什么事?
其实很简单。moment是一个 JavaScript 库,它已经包含在我们 Node 项目的 ` .node`或 ` package.json.node.js` 文件中。如果您是 Node 新手,还不熟悉 moment ,请点击此处了解更多信息。dependenciesdevDependenciespackage.json
这行代码创建了一个对moment库中所有可用资源的引用,并将其放入一个变量中,以便我们可以访问它。'moment'引号内的部分告诉编译器要使用哪个库。另一部分moment(未加引号)是变量本身。因此,从这里开始,我们可以像访问文件中的任何其他变量一样访问 moment:
import moment from 'moment';
console.log(
moment().get('year')
);
// 2019
不为人知的部分
moment在幕后,这只是将库通过export default 其主文件提供的所有内容都放入一个变量中——而该变量可以具有我们想要的任何有效名称!
这可能有点令人困惑,但如果你觉得这个名字更有意义,你完全可以这样做:
import ThatReallyUsefulDateLibrary from 'moment';
console.log(
ThatReallyUsefulDateLibrary().get('year')
);
// 2019
从库中的某个位置导入组件
接下来——这个稍微复杂一些的家伙:
import Button from '@material-ui/core/Button';
这里我们<Button />从@material-ui库中获取组件。这很简单,但从 material-ui 项目的结构来理解可能会有所帮助。Material-ui 导出了很多很棒的东西,而且它们都按照逻辑分组组织起来。可以这样理解:
// material-ui exports
const muiExports = {
core: {
Button: () => {}, // some component
TextField: () => {} // another useful component
// and loads more
}
}
通过上面的导入语法Button,我们告诉编译器提供一个指向名为 `<output_name>` 的导出对象的引用Button,该对象位于@material-ui库的 `<output_name>` 目录下/core/Button。编译器本质上将其视为上面代码片段中的 JSON 对象。
关键在于——这也意味着我们可以对其进行解构!😁。这种语法也适用于导入Button:
import { Button } from '@material-ui/core';
这也意味着我们可以在一行代码中导入多个文件!/core
import { Button, TextField} from '@material-ui/core';
很酷吧?我知道这可能有点让人困惑,但请坚持下去。很快你就会明白了。接下来我们来看下一个例子:
通过解构导入库的子集
import { Link } from 'gatsby';
搞定!现在应该很简单了。它Gatsby提供的其中一项功能就是他们的link组件。我们这里只需要导入这个组件就可以了。
重命名导入
但是,如果我们Link的项目中已经存在一个名为 `<component>` 的组件呢?或者,如果我们正在制作一个《塞尔达传说》的粉丝网站,而 `<component>`已经在某个我们无法重命名的组件或变量中定义好了呢?其实,在导入语句中重命名元素和在解构语句中重命名元素一样简单。我们可以像这样Link重命名同一个组件:gatsby
import { Link as GatsbyWebLink } from 'gatsby';
我们还可以在一条语句中重命名一个或多个解构导入:
import {
Link as GatsbyWebLink,
graphql as graphqlQuery,
useStaticQuery
} from 'gatsby';
小菜一碟!🍰
相对导入
还有一点需要注意——如果你在导入位置字符串中使用相对路径,编译器就知道该查找你导出的内容了:
import { Layout } from '../components';
就像其他任何地方一样,你可以在这里随心所欲地组合和重命名内容:
import {
Layout,
Button as SuperButton
} from '../components';
把所有东西整合起来
最好的并不总是最后出现的,但这确实是我今天要分享的最后一个例子:
import React, { useState, useEffect } from 'react';
如果你一直在家跟着做,现在应该对这一切很熟悉了——我们从 `<lib>` 中获取了默认导出react,并将其放入了变量 `<variable>` 中react。我们还解构了来自同一库的 `<class>`useState和`<class> `。如果你在想“我们难道不能把它作为 `<class>` 的子类来访问吗?”,答案是——实际上,是的!useEffectuseStateReact
这完全合理。
const [loading, setLoading] = React.useState(false);
……但打字和阅读起来都不如……
const [loading, setLoading] = useState(false);
从执行角度来看,两者功能相同,但后者是按惯例使用的。
我想就是这样了。
我想应该是这样。事实证明,写这篇文章真的挺棘手的——导入文件的方法数不胜数,而且我可能漏掉了许多情况。这里展示的某些导入语法肯定会对性能和包大小产生影响。虽然这些都是实实在在的限制,而且会对应用程序的性能产生实际影响,但为了简洁起见,我决定把这些讨论留到以后再说。
还有一个不容忽视的问题:目前使用import 语句require()需要像 Babel 或 Webpack 这样的转译器。这又是一个极其复杂的领域,我不确定自己是否有能力在一篇博文中解释清楚。这也意味着我没有展示上述语法是如何与 Node.js 配合使用的。坦白说,这方面需要解释的内容实在太多了——未来 EcmaScript 和 Node.js 的改进将会使一切变得更好。
打个招呼!
和往常一样,如果我哪里说错了,请务必告诉我!给我发个消息吧@irreverentmike。我很想听听你的意见。👋
信用
本文封面照片的背景图来自Unsplash 网站的Ricardo Viana。感谢您的精彩作品!
文章来源:https://dev.to/irreverentmike/picking-apart-javascript-import-syntax-e5o