ECMAScript 6 中更短的 class 初始化
A shorter class initialisation in ECMAScript 6
每次我创建一些 class,我都需要做同样无聊的过程:
class Something {
constructor(param1, param2, param3, ...) {
this.param1 = param1;
this.param2 = param2;
this.param3 = param3;
...
}
}
有什么办法让它更优雅更短吗?我使用 Babel,因此允许使用一些 ES7 实验性功能。也许装饰器可以提供帮助?
您可以使用 Object.assign
:
class Something {
constructor(param1, param2, param3) {
Object.assign(this, {param1, param2, param3});
}
}
这是一项 ES2015(又名 ES6)功能,可将一个或多个源对象的 自己的可枚举 属性分配给目标对象。
当然,您必须将 arg 名称写两次,但至少它要短得多,并且如果您将此设置为您的惯用语,当您在实例上有您确实需要的参数和其他您想要的参数时,它会很好地处理它不要,例如:
class Something {
constructor(param1, param2, param3) {
Object.assign(this, {param1, param3});
// ...do something with param2, since we're not keeping it as a property...
}
}
示例:(live copy on Babel's REPL):
class Something {
constructor(param1, param2, param3) {
Object.assign(this, {param1, param2, param3});
}
}
let s = new Something('a', 'b', 'c');
console.log(s.param1);
console.log(s.param2);
console.log(s.param3);
输出:
a
b
c
不幸的是,你所能做的只是像 Object.assign
这样的简单事情,但是如果你试图消除两次输入所有参数的冗余(一次在构造函数签名中,一次在赋值中),那么'你无能为力。
就是说,您可以像这样破解。尽管我不确定随之而来的努力和少量混淆是否值得。
var dependencies = ['param1', 'param2', 'param3'];
class Something {
constructor(...params) {
params.forEach((param, index) => this[dependencies[index]] = param);
}
}
var something = new Something('foo', 'bar', 'baz');
// something.param1 === 'foo'
这样您就可以使用单个参数名称数组,然后在 Something
的实例上创建属性时使用相同的数组作为参考。这种模式在 Angular 应用程序中会很好地工作,在该应用程序中,您试图通过设置 $inject
属性.
通过缩小来保留依赖项名称
Something.$inject = dependencies;
PS - 欢迎来到我 认为 我成为 JS 开发人员时远离的 class 语言的冗余地狱 :P
老实说,你应该只使用 classic 对象字面量,除非你真的需要正式的 class.
编辑:我想你可以在你的构造函数中接受一个对象文字,如果你想要文字的易用性 和 实际 class 的形式。
class Something {
constructor(params) {
Object.keys(params).forEach((name) => this[name] = params[name]);
}
}
var something = new Something({
param1: 'foo',
param2: 'bar',
param3: 'baz'
});
但是现在您刚刚将 class 变成了可以用任何属性实例化的动态 class,有点像对象字面量 :P
通常我想要一个class,因为我想形式化对象并呈现一致且严格可测试的API。
我们可以在每个 class 中创建一个静态方法,它接受 arguments
对象和一个名称数组,以及 returns 一个可以分配给新实例的对象 Object.assign
。
使用 Babel REPL 查看它。
class Something {
static buildArgs (ctx, args, paramNames) {
let obj = {}
Array.from(args).forEach(function (arg, i) {
let name = paramNames[i] || i
obj[name] = args[i]
})
Object.assign(ctx, obj)
}
constructor () {
Something.buildArgs(this, arguments, [
'param1',
'param2'
]);
console.log(this)
}
}
new Something('one', 'two')
诚然,添加方法 buildArgs
意味着这个解决方案并不短,但是 constructor
的主体是,我们也有这些优势:
- 您只写了一次参数名称。
- 您不会被缩小。
上面的代码包含额外的参数 (i >= paramNames.length
),但是如果这种行为是不可取的,我们可以修改它,以便这些仍然被解析,但不会分配给实例:
class Something {
static buildArgs (ctx, args, paramNames) {
let obj = {instance: {}, extra: {}}
Array.from(args).forEach(function (arg, i) {
let name = paramNames[i] || i
if (name) {
obj.instance[name] = args[i]
} else {
obj.extra[i] = args[i]
}
})
Object.assign(ctx, obj)
}
constructor () {
let args = Something.buildArgs(this, arguments, ['param1', 'param2']);
// Do stuff with `args.extra`
}
}
或完全忽略:
static buildArgs (args, paramNames) {
let obj = {}
Array.from(args).forEach(function (arg, i) {
let name = paramNames[i]
if (name) obj[name] = args[i]
})
return obj
}
每次我创建一些 class,我都需要做同样无聊的过程:
class Something {
constructor(param1, param2, param3, ...) {
this.param1 = param1;
this.param2 = param2;
this.param3 = param3;
...
}
}
有什么办法让它更优雅更短吗?我使用 Babel,因此允许使用一些 ES7 实验性功能。也许装饰器可以提供帮助?
您可以使用 Object.assign
:
class Something {
constructor(param1, param2, param3) {
Object.assign(this, {param1, param2, param3});
}
}
这是一项 ES2015(又名 ES6)功能,可将一个或多个源对象的 自己的可枚举 属性分配给目标对象。
当然,您必须将 arg 名称写两次,但至少它要短得多,并且如果您将此设置为您的惯用语,当您在实例上有您确实需要的参数和其他您想要的参数时,它会很好地处理它不要,例如:
class Something {
constructor(param1, param2, param3) {
Object.assign(this, {param1, param3});
// ...do something with param2, since we're not keeping it as a property...
}
}
示例:(live copy on Babel's REPL):
class Something {
constructor(param1, param2, param3) {
Object.assign(this, {param1, param2, param3});
}
}
let s = new Something('a', 'b', 'c');
console.log(s.param1);
console.log(s.param2);
console.log(s.param3);
输出:
a b c
不幸的是,你所能做的只是像 Object.assign
这样的简单事情,但是如果你试图消除两次输入所有参数的冗余(一次在构造函数签名中,一次在赋值中),那么'你无能为力。
就是说,您可以像这样破解。尽管我不确定随之而来的努力和少量混淆是否值得。
var dependencies = ['param1', 'param2', 'param3'];
class Something {
constructor(...params) {
params.forEach((param, index) => this[dependencies[index]] = param);
}
}
var something = new Something('foo', 'bar', 'baz');
// something.param1 === 'foo'
这样您就可以使用单个参数名称数组,然后在 Something
的实例上创建属性时使用相同的数组作为参考。这种模式在 Angular 应用程序中会很好地工作,在该应用程序中,您试图通过设置 $inject
属性.
Something.$inject = dependencies;
PS - 欢迎来到我 认为 我成为 JS 开发人员时远离的 class 语言的冗余地狱 :P
老实说,你应该只使用 classic 对象字面量,除非你真的需要正式的 class.
编辑:我想你可以在你的构造函数中接受一个对象文字,如果你想要文字的易用性 和 实际 class 的形式。
class Something {
constructor(params) {
Object.keys(params).forEach((name) => this[name] = params[name]);
}
}
var something = new Something({
param1: 'foo',
param2: 'bar',
param3: 'baz'
});
但是现在您刚刚将 class 变成了可以用任何属性实例化的动态 class,有点像对象字面量 :P
通常我想要一个class,因为我想形式化对象并呈现一致且严格可测试的API。
我们可以在每个 class 中创建一个静态方法,它接受 arguments
对象和一个名称数组,以及 returns 一个可以分配给新实例的对象 Object.assign
。
使用 Babel REPL 查看它。
class Something {
static buildArgs (ctx, args, paramNames) {
let obj = {}
Array.from(args).forEach(function (arg, i) {
let name = paramNames[i] || i
obj[name] = args[i]
})
Object.assign(ctx, obj)
}
constructor () {
Something.buildArgs(this, arguments, [
'param1',
'param2'
]);
console.log(this)
}
}
new Something('one', 'two')
诚然,添加方法 buildArgs
意味着这个解决方案并不短,但是 constructor
的主体是,我们也有这些优势:
- 您只写了一次参数名称。
- 您不会被缩小。
上面的代码包含额外的参数 (i >= paramNames.length
),但是如果这种行为是不可取的,我们可以修改它,以便这些仍然被解析,但不会分配给实例:
class Something {
static buildArgs (ctx, args, paramNames) {
let obj = {instance: {}, extra: {}}
Array.from(args).forEach(function (arg, i) {
let name = paramNames[i] || i
if (name) {
obj.instance[name] = args[i]
} else {
obj.extra[i] = args[i]
}
})
Object.assign(ctx, obj)
}
constructor () {
let args = Something.buildArgs(this, arguments, ['param1', 'param2']);
// Do stuff with `args.extra`
}
}
或完全忽略:
static buildArgs (args, paramNames) {
let obj = {}
Array.from(args).forEach(function (arg, i) {
let name = paramNames[i]
if (name) obj[name] = args[i]
})
return obj
}