来自交叉依赖的默认参数未定义
Default parameters from cross dependency is undefined
我有两个相互依赖的文件:
runner.js
import { build, altBuild } from './build';
const defaultValue = {
code: 42,
};
export function options(value = defaultValue) {
return value;
}
export function altOptions(value = { code: 9 }) {
return value;
}
console.log(build());
console.log(altBuild());
build.js
import { options, altOptions } from './runner';
const buildParams = {
foo: 'bar',
extra: options(),
}
const altBuildParams = {
foo: 'bar',
extra: altOptions(),
}
export function build() {
console.log(options());
return buildParams;
}
export function altBuild() {
console.log(altOptions());
return altBuildParams;
}
当 运行ning 时,我希望输出为:
{ code: 42 }
{ foo: 'bar', extra: { code: 42 } }
{ code: 9 }
{ foo: 'bar', extra: { code: 9 } }
但它是:
{ code: 42 }
{ foo: 'bar', extra: undefined }
{ code: 9 }
{ foo: 'bar', extra: { code: 9 } }
我可以解决这个问题,但我真的很好奇为什么会这样。我正在使用 Node 7.10 和 babel-node 6.26 来 运行 这个例子。
使用转译后的代码更新:
转译runner.js
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.options = options;
exports.altOptions = altOptions;
var _build = require('./build');
var defaultValue = {
code: 42
};
function options() {
var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultValue;
return value;
}
function altOptions() {
var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { code: 9 };
return value;
}
console.log((0, _build.build)());
console.log((0, _build.altBuild)());
转译build.js
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.build = build;
exports.altBuild = altBuild;
var _runner = require('./runner');
var buildParams = {
foo: 'bar',
extra: (0, _runner.options)()
};
var altBuildParams = {
foo: 'bar',
extra: (0, _runner.altOptions)()
};
function build() {
console.log((0, _runner.options)());
return buildParams;
}
function altBuild() {
console.log((0, _runner.altOptions)());
return altBuildParams;
}
在循环依赖中,虽然函数 声明 可以立即用于所有其他需要初始化顺序的东西。这不会按需发生(惰性),而是按导入顺序定义,然后评估完整的模块主体。
在你的情况下,取决于首先需要哪个文件,你可以
- 得到
defaultValue
初始化对象
- 调用
build()
,得到 options()
就好了,然后引用未初始化的 buildParams
,并记录结果
- 调用
build()
,得到 altOptions()
就好了,然后引用未初始化的 altBuildParams
,并记录结果
- get
buildParams
用 options()
初始化得到 defaultValue
- 用
altOptions()
初始化altBuildParams
或
- get
buildParams
initialised with options()
指的是未初始化的 defaultValue
- 用
altOptions()
初始化altBuildParams
- 得到
defaultValue
初始化对象
- 调用
build()
,获取 options()
并使用 buildParams
,并记录结果
- 调用
build()
,获取 altOptions()
并使用 altBuildParams
,并记录结果
在任何一种情况下,你都引用了一个未初始化的变量,它会在真正的 ES6 中抛出异常,但在 babel 转换中只会以 undefined
结束。你无法完成这项工作。
一般来说,只在有循环依赖的模块中使用函数声明,不要在模块顶层范围内调用任何东西(包括变量初始化)。确保代码至少可以放在一个大文件中。
我有两个相互依赖的文件:
runner.js
import { build, altBuild } from './build';
const defaultValue = {
code: 42,
};
export function options(value = defaultValue) {
return value;
}
export function altOptions(value = { code: 9 }) {
return value;
}
console.log(build());
console.log(altBuild());
build.js
import { options, altOptions } from './runner';
const buildParams = {
foo: 'bar',
extra: options(),
}
const altBuildParams = {
foo: 'bar',
extra: altOptions(),
}
export function build() {
console.log(options());
return buildParams;
}
export function altBuild() {
console.log(altOptions());
return altBuildParams;
}
当 运行ning 时,我希望输出为:
{ code: 42 }
{ foo: 'bar', extra: { code: 42 } }
{ code: 9 }
{ foo: 'bar', extra: { code: 9 } }
但它是:
{ code: 42 }
{ foo: 'bar', extra: undefined }
{ code: 9 }
{ foo: 'bar', extra: { code: 9 } }
我可以解决这个问题,但我真的很好奇为什么会这样。我正在使用 Node 7.10 和 babel-node 6.26 来 运行 这个例子。
使用转译后的代码更新:
转译runner.js
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.options = options;
exports.altOptions = altOptions;
var _build = require('./build');
var defaultValue = {
code: 42
};
function options() {
var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultValue;
return value;
}
function altOptions() {
var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { code: 9 };
return value;
}
console.log((0, _build.build)());
console.log((0, _build.altBuild)());
转译build.js
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.build = build;
exports.altBuild = altBuild;
var _runner = require('./runner');
var buildParams = {
foo: 'bar',
extra: (0, _runner.options)()
};
var altBuildParams = {
foo: 'bar',
extra: (0, _runner.altOptions)()
};
function build() {
console.log((0, _runner.options)());
return buildParams;
}
function altBuild() {
console.log((0, _runner.altOptions)());
return altBuildParams;
}
在循环依赖中,虽然函数 声明 可以立即用于所有其他需要初始化顺序的东西。这不会按需发生(惰性),而是按导入顺序定义,然后评估完整的模块主体。
在你的情况下,取决于首先需要哪个文件,你可以
- 得到
defaultValue
初始化对象 - 调用
build()
,得到options()
就好了,然后引用未初始化的buildParams
,并记录结果 - 调用
build()
,得到altOptions()
就好了,然后引用未初始化的altBuildParams
,并记录结果 - get
buildParams
用options()
初始化得到defaultValue
- 用
altOptions()
初始化
altBuildParams
或
- get
buildParams
initialised withoptions()
指的是未初始化的defaultValue
- 用
altOptions()
初始化 - 得到
defaultValue
初始化对象 - 调用
build()
,获取options()
并使用buildParams
,并记录结果 - 调用
build()
,获取altOptions()
并使用altBuildParams
,并记录结果
altBuildParams
在任何一种情况下,你都引用了一个未初始化的变量,它会在真正的 ES6 中抛出异常,但在 babel 转换中只会以 undefined
结束。你无法完成这项工作。
一般来说,只在有循环依赖的模块中使用函数声明,不要在模块顶层范围内调用任何东西(包括变量初始化)。确保代码至少可以放在一个大文件中。