使用 ES6 语法将包导入为另一个包的扩展

Import a package as an extension of another package with ES6 syntax

为了在 D3 中扩展地图投影,建议需要这样的包:

const d3 = require("d3")
require("d3-geo-projection")(d3)

这样,您可以使用例如来自父包的 d3-geo-projectiongeoAiry 方法:

d3.geoAiry()

使用 import 我正在这样做:

import * as d3 from 'd3'
import * as d3geo from 'd3-geo-projection'

但是后来方法不统一:

d3.geoMercator()
d3geo.geoAiry()

我试过了,但没用:

import * as d3 from 'd3'
import * as d3geo from 'd3-geo-projection'
d3geo(d3)

那么,简而言之,ES6 语法中的 require("d3-geo-projection")(d3) 等价于什么?

从技术上讲,您可以使用 d3.assign() 将所有属性从一个导入复制到另一个导入。

import * as d3 from 'd3';
import * as d3geo from 'd3-geo-projection';

Object.assign(d3, d3geo);

这将使您的所有属性在您要求的 d3 对象下可用:

d3.geoMercator()
d3.geoAiry()
// ...

但是,你应该那样做吗?在我看来,您应该避免将两个导入聚合到一个对象中。这似乎是许多开发人员屈服于 ES6 之前的一些反应,因为他们被教导这样做,以通过将代码汇总到对象中来确保封装。不过,随着模块的引入,JS 中封装的概念略有改变。

Mike Bostok 本人对他在 GitHub issue 的回答中描述的问题有自己的看法,该问题正是处理您发布的问题。他鼓励完全放弃 import * as d3 的使用,转而只导入您实际要使用的模块的那些部分。就我个人而言,我支持该建议,因为我认为为了清晰和简洁起见,这是现代 JS 代码中应该使用模块的方式。对于我自己的代码,我愿意接受的唯一例外是使用了很多(比如 20 多个)来自单个模块的导出成员,尽管这也可能表明有一些代码味道,建议您考虑重构自己的模块把它分解成更小的部分。

为了更加模块化,我通常更喜欢使用单个模块而不是整个 d3 包,如下所示:

import { select, selectAll } from "d3-selection";
import { min, max } from "d3-array";
import { geoAiry } from "d3-geo-projection";
// ...