目前在ES5中,我们很多人在框架中使用以下模式来创建类和类变量,这很舒服:
// ES 5
FrameWork.Class({
variable: 'string',
variable2: true,
init: function(){
},
addItem: function(){
}
});
在ES6中,你可以在本地创建类,但是没有选项可以有类变量:
// ES6
class MyClass {
const MY_CONST = 'string'; // <-- this is not possible in ES6
constructor(){
this.MY_CONST;
}
}
遗憾的是,上述方法不起作用,因为类只能包含方法。
我知道我能做到。myVar = true在构造函数…但我不想'垃圾'我的构造函数,特别是当我有20-30+参数为一个更大的类。
我想了很多方法来处理这个问题,但还没有找到一个好的。(例如:创建一个ClassConfig处理程序,并传递一个参数对象,该对象与类分开声明。然后处理程序将附加到类。我也在考虑以某种方式集成WeakMaps。)
你会有什么样的想法来处理这种情况?
只是补充一下本杰明的答案——类变量是可能的,但你不会使用原型来设置它们。
对于一个真正的类变量,你应该像下面这样做:
class MyClass {}
MyClass.foo = 'bar';
在类方法中,该变量可以通过this.constructor.foo(或MyClass.foo)访问。
这些类属性通常不能被类实例访问。即MyClass。foo给出'bar'但新的MyClass()。Foo没有定义
如果你也想从实例中访问你的类变量,你必须另外定义一个getter:
class MyClass {
get foo() {
return this.constructor.foo;
}
}
MyClass.foo = 'bar';
我只在Traceur上测试过这个功能,但我相信它在标准实现中也能发挥同样的作用。
JavaScript实际上没有类。即使在ES6中,我们看到的是基于对象或原型的语言,而不是基于类的语言。在任何函数X(){}中,X.prototype.constructor都指向X。
当在X上使用new操作符时,将创建一个继承X.prototype的新对象。新对象中任何未定义的属性(包括构造函数)都将从那里查找。我们可以把这看作是生成对象和类属性。
我解决这个问题的方法,这是另一个选择(如果你有jQuery可用),是在一个老式的对象中定义字段,然后用该对象扩展类。我也不想在构造函数中添加赋值,这似乎是一个整洁的解决方案。
function MyClassFields(){
this.createdAt = new Date();
}
MyClassFields.prototype = {
id : '',
type : '',
title : '',
createdAt : null,
};
class MyClass {
constructor() {
$.extend(this,new MyClassFields());
}
};
——根据Bergi的评论更新。
没有JQuery版本:
class SavedSearch {
constructor() {
Object.assign(this,{
id : '',
type : '',
title : '',
createdAt: new Date(),
});
}
}
你仍然会得到“胖”构造函数,但至少它都在一个类中,并在一次命中赋值。
编辑# 2:
我现在已经走了一圈,现在在构造函数中赋值,例如。
class SavedSearch {
constructor() {
this.id = '';
this.type = '';
this.title = '';
this.createdAt = new Date();
}
}
为什么?真的很简单,使用上面的加上一些JSdoc注释,PHPStorm就能够在属性上执行代码补全。在一次命中分配所有的变量是很好的,但无法编码完成属性,在我看来,不值得(几乎肯定是微乎其微的)性能收益。
在你的例子中:
class MyClass {
const MY_CONST = 'string';
constructor(){
this.MY_CONST;
}
}
因为MY_CONST是原始的https://developer.mozilla.org/en-US/docs/Glossary/Primitive,我们可以这样做:
class MyClass {
static get MY_CONST() {
return 'string';
}
get MY_CONST() {
return this.constructor.MY_CONST;
}
constructor() {
alert(this.MY_CONST === this.constructor.MY_CONST);
}
}
alert(MyClass.MY_CONST);
new MyClass
// alert: string ; true
但如果MY_CONST是引用类型,如静态get MY_CONST() {return ['string'];}警报输出是字符串,false。在这种情况下,删除操作符可以做到:
class MyClass {
static get MY_CONST() {
delete MyClass.MY_CONST;
return MyClass.MY_CONST = 'string';
}
get MY_CONST() {
return this.constructor.MY_CONST;
}
constructor() {
alert(this.MY_CONST === this.constructor.MY_CONST);
}
}
alert(MyClass.MY_CONST);
new MyClass
// alert: string ; true
最后对于非const类变量:
class MyClass {
static get MY_CONST() {
delete MyClass.MY_CONST;
return MyClass.MY_CONST = 'string';
}
static set U_YIN_YANG(value) {
delete MyClass.MY_CONST;
MyClass.MY_CONST = value;
}
get MY_CONST() {
return this.constructor.MY_CONST;
}
set MY_CONST(value) {
this.constructor.MY_CONST = value;
}
constructor() {
alert(this.MY_CONST === this.constructor.MY_CONST);
}
}
alert(MyClass.MY_CONST);
new MyClass
// alert: string, true
MyClass.MY_CONST = ['string, 42']
alert(MyClass.MY_CONST);
new MyClass
// alert: string, 42 ; true
ES7类成员语法:
ES7有一个“废弃”构造函数的解决方案。这里有一个例子:
车{
轮子= 4;
重量= 100;
}
const car = new car ();
console.log(车。轮子,car.weight);
上面的例子在ES6中看起来如下所示:
车{
构造函数(){
这一点。轮子= 4;
这一点。重量= 100;
}
}
const car = new car ();
console.log(车。轮子,car.weight);
使用此语法时请注意,此语法可能不是所有浏览器都支持,可能必须转译为早期版本的JS。
好处:一个对象工厂:
函数generateCar(车轮,重量){
车{
构造函数(){}
轮子=轮子;
重量=重量;
}
返回新车();
}
const car1 = generateCar(4,50);
const car2 = generateCar(6,100);
console.log (car1。轮子,car1.weight);
console.log (car2。轮子,car2.weight);
正如Benjamin在他的回答中所说,TC39明确决定至少在ES2015中不包含这个功能。然而,共识似乎是他们将在ES2016中添加它。
语法还没有决定,但是ES2016已经有了一个初步的提议,允许你在一个类上声明静态属性。
多亏了巴别塔的魔力,你今天可以使用它。根据这些说明启用类属性转换,就可以开始了。下面是一个语法示例:
class foo {
static myProp = 'bar'
someFunction() {
console.log(this.myProp)
}
}
这个建议还处于非常早期的状态,所以准备好随着时间的推移调整您的语法。