ES6类变量替代

2020/09/25 09:21 · javascript ·  · 0评论

当前,在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;
    }
}

可悲的是,上述方法不起作用,因为类只能包含方法。

我知道我可以this.myVar = trueconstructor...但我不想“垃圾”我的构造,特别是当我有一个更大的类20-30 +参数。

我在考虑解决该问题的许多方法,但尚未找到任何好的方法。(例如:创建一个ClassConfig处理程序,并传递一个parameter与类分开声明对象。然后该处理程序将附加到该类。我也在考虑WeakMaps通过某种方式进行集成。)

您将如何处理这种情况?

2018更新:

现在有第3阶段的提案-我期待在几个月后使这个答案过时。

同时,使用TypeScript或babel的任何人都可以使用以下语法:

varName = value

在类声明/表达式主体内,它将定义一个变量。希望在几个月/几周内,我将能够发布更新。

更新:Chrome 74现在附带此语法。


ES Wiki中针对ES6中提案的注释(最大类别)注释:

没有(有意地)没有直接的声明方式来定义原型数据属性(方法以外的类)或实例属性

类属性和原型数据属性需要在声明之外创建。

在类定义中指定的属性被赋予相同的属性,就像它们出现在对象文字中一样。

这意味着您的要求已被考虑,并明确决定反对。

但为什么?

好问题。TC39的好人希望类声明声明和定义类的功能。不是它的成员。ES6类声明为其用户定义其合同。

请记住,类定义定义了原型方法-在原型上定义变量通常不是您要做的事情。您当然可以使用:

constructor(){
    this.foo = bar
}

在您建议的构造函数中。另请参见共识摘要

ES7及更高版本

对正在工作了ES7一项新的提案,通过类的声明和表达式可以更简洁的实例变量- https://esdiscuss.org/topic/es7-property-initializers

只是为了增加本杰明的答案-类变量是可能的,但您不会用它prototype来设置它们。

对于真正的类变量,您需要执行以下操作:

class MyClass {}
MyClass.foo = 'bar';

在类方法中,可以按this.constructor.foo(或MyClass.foo访问变量

这些类属性通常无法从类实例访问。MyClass.foo给人'bar'new MyClass().fooundefined

如果您还想从实例访问类变量,则必须另外定义一个getter:

class MyClass {
    get foo() {
        return this.constructor.foo;
    }
}

MyClass.foo = 'bar';

我仅使用Traceur进行了此测试,但我相信它在标准实现中将发挥相同的作用。

JavaScript确实没有类即使使用ES6,我们也在研究基于对象或原型的语言,而不是基于类的语言。在任何情况下function X () {},都X.prototype.constructor指向X使用new运算符时X,将继承创建一个新对象X.prototype从那里查找该新对象(包括中)中所有未定义的属性constructor我们可以将其视为生成对象和类的属性。

Babel在ESNext中支持类变量,请查看以下示例

class Foo {
  bar = 2
  static iha = 'string'
}

const foo = new Foo();
console.log(foo.bar, foo.iha, Foo.bar, Foo.iha);
// 2, undefined, undefined, 'string'

在您的示例中:

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_CONSTstatic get MY_CONST() {return ['string'];}警报输出这样的引用类型string,则为false在这种情况下,delete操作员可以做到这一点:

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

由于您的问题主要是风格问题(不想用一堆声明填充构造函数),因此也可以从样式上解决。

我的看法是,许多基于类的语言都将构造函数作为以类名本身命名的函数。从风格上讲,我们可以使用它来使ES6类在风格上仍然有意义,但不会将构造函数中发生的典型动作与我们正在执行的所有属性声明进行分组。我们只使用实际的JS构造函数作为“声明区域”,然后创建一个名为function的类,否则将其视为“其他构造函数”区域,在真正的构造函数的末尾调用它。

“使用严格”;

类MyClass
{
    //仅声明您的属性,然后调用this.ClassName(); 从这里
    构造函数(){
        this.prop1 ='blah 1';
        this.prop2 ='blah 2';
        this.prop3 ='blah 3';
        this.MyClass();
    }

    //各种其他“构造函数”的东西,不再与声明混为一谈
    我的课() {
        doWhatever();
    }
}

两者都将在构造新实例时被调用。

Sorta就像有2个构造函数,您可以在其中分离声明和要执行的其他构造函数,从样式上也可以很容易地理解这是怎么回事。

我发现在处理大量声明和/或在实例化时需要执行的许多动作以及希望使这两种想法彼此不同时,可以使用一种不错的样式。


注意:我非常有目的地不使用“初始化”的典型惯用想法(如an init()initialize()method),因为它们经常以不同的方式使用。构造和初始化的概念之间存在某种假定的差异。与构造函数一起工作的人们知道,它们在实例化过程中被自动调用。看到init许多人会不假思索地假定他们需要做某种形式的方法var mc = MyClass(); mc.init();,因为这通常是您初始化的方式。我不是要为类的用户添加初始化过程,而是要添加类本身的构造过程中。

尽管有些人可能会花一会儿时间,但这实际上是重点:它向他们传达了意图是建设的一部分,即使这会使他们做一番重复即走。“那不是ES6构造函数的工作原理”,然后再看一下实际的构造函数,“哦,我知道它们是在底部”,这比不传达意图(或错误传达)要好得多,人们使用它是错误的,试图从外部和垃圾中初始化它。这是我建议的模式非常有意的。


对于那些不想遵循这种模式的人,完全相反的做法也可以。在开始时将声明植入另一个函数。也许将其命名为“属性”或“ publicProperties”或其他名称。然后将其余内容放入普通的构造函数中。

“使用严格”;

类MyClass
{
    properties(){
        this.prop1 ='blah 1';
        this.prop2 ='blah 2';
        this.prop3 ='blah 3';
    }

    constructor(){
        this.properties();
        doWhatever();
    }
}

请注意,第二种方法看起来更简洁,但也存在一个固有的问题,即properties当使用该方法的一个类扩展了另一个方法时,该方法将被覆盖。您必须提供更多唯一的名称properties来避免这种情况。我的第一个方法没有这个问题,因为其假的构造函数的一半以类唯一命名。

那老式的方式呢?

class MyClass {
     constructor(count){ 
          this.countVar = 1 + count;
     }
}
MyClass.prototype.foo = "foo";
MyClass.prototype.countVar = 0;

// ... 

var o1 = new MyClass(2); o2 = new MyClass(3);
o1.foo = "newFoo";

console.log( o1.foo,o2.foo);
console.log( o1.countVar,o2.countVar);

在构造函数中,您仅提及那些必须计算的变量。我喜欢此功能的原型继承-它可以帮助节省大量内存(以防万一有很多从未分配的var)。

正如本杰明在回答中所说,TC39明确决定至少在ES2015中不包括此功能。但是,共识似乎是他们将在ES2016中添加它。

语法尚未确定,但是ES2016 有一个初步建议,可让您在类上声明静态属性。

感谢babel的魔力,您今天就可以使用它。根据这些说明启用类属性转换,您可以开始进行。这是语法示例:

class foo {
  static myProp = 'bar'
  someFunction() {
    console.log(this.myProp)
  }
}

该提案处于早期状态,因此请准备好随着时间的流逝调整语法。

[长线程,不确定它是否已作为选项列出...]。

一个简单的
替代的用于contsants只,将定义类的常量外部。除非带有吸气剂,否则只能从模块本身进行访问。

这种方法
prototype不会乱扔垃圾,您会得到const

// will be accessible only from the module itself
const MY_CONST = 'string'; 
class MyClass {

    // optional, if external access is desired
    static get MY_CONST(){return MY_CONST;}

    // access example
    static someMethod(){
        console.log(MY_CONST);
    }
}

ES7 类成员语法:

ES7有一个解决方案“垃圾”您的构造函数。这是一个例子:

class Car {
  
  wheels = 4;
  weight = 100;

}

const car = new Car();
console.log(car.wheels, car.weight);

上面的示例将在中显示以下内容ES6

class Car {

  constructor() {
    this.wheels = 4;
    this.weight = 100;
  }

}

const car = new Car();
console.log(car.wheels, car.weight);

请注意,使用此方法时,并非所有浏览器都支持此语法,并且可能必须将其编译为JS的早期版本。

奖励:对象工厂:

function generateCar(wheels, weight) {

  class Car {

    constructor() {}

    wheels = wheels;
    weight = weight;

  }

  return new Car();

}


const car1 = generateCar(4, 50);
const car2 = generateCar(6, 100);

console.log(car1.wheels, car1.weight);
console.log(car2.wheels, car2.weight);

您可以模仿es6类的行为...并使用类变量:)

看妈妈...没有课!

// Helper
const $constructor = Symbol();
const $extends = (parent, child) =>
  Object.assign(Object.create(parent), child);
const $new = (object, ...args) => {
  let instance = Object.create(object);
  instance[$constructor].call(instance, ...args);
  return instance;
}
const $super = (parent, context, ...args) => {
  parent[$constructor].call(context, ...args)
}
// class
var Foo = {
  classVariable: true,

  // constructor
  [$constructor](who){
    this.me = who;
    this.species = 'fufel';
  },

  // methods
  identify(){
    return 'I am ' + this.me;
  }
}

// class extends Foo
var Bar = $extends(Foo, {

  // constructor
  [$constructor](who){
    $super(Foo, this, who);
    this.subtype = 'barashek';
  },

  // methods
  speak(){
    console.log('Hello, ' + this.identify());
  },
  bark(num){
    console.log('Woof');
  }
});

var a1 = $new(Foo, 'a1');
var b1 = $new(Bar, 'b1');
console.log(a1, b1);
console.log('b1.classVariable', b1.classVariable);

我把它放在GitHub上

我解决此问题的方法是另一种选择(如果您可以使用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(),
        });

    }
}

您仍然会得到“ fat”构造函数,但至少将其全部放在一个类中并一次命中。

编辑#2:
我现在走了一个完整的圈子,现在正在构造函数中分配值,例如

class SavedSearch  {
    constructor() {
        this.id = '';
        this.type = '';
        this.title = '';
        this.createdAt = new Date();
    }
}

为什么?实际上,很简单,使用上面的代码和一些JSdoc注释,PHPStorm能够对属性执行代码完成。一次命中分配所有变量很不错,但是无法编写完整的属性imo不值得(几乎肯定是很小的)性能好处。

好了,您可以在构造函数中声明变量。

class Foo {
    constructor() {
        var name = "foo"
        this.method = function() {
            return name
        }
    }
}

var foo = new Foo()

foo.method()

仍然不能像使用其他编程语言一样声明任何类。但是您可以创建尽可能多的类变量。但是问题是类对象的范围。因此,根据我的观点,ES6 Javascript中OOP编程的最佳方式:

class foo{
   constructor(){
     //decalre your all variables
     this.MY_CONST = 3.14;
     this.x = 5;
     this.y = 7;
     // or call another method to declare more variables outside from constructor.
     // now create method level object reference and public level property
     this.MySelf = this;
     // you can also use var modifier rather than property but that is not working good
     let self = this.MySelf;
     //code ......... 
   }
   set MySelf(v){
      this.mySelf = v;
   }
   get MySelf(v){
      return this.mySelf;
   }
   myMethod(cd){
      // now use as object reference it in any method of class
      let self = this.MySelf;
      // now use self as object reference in code
   }
}

如果仅仅是混乱的话,constructor为什么不实现变量initialize方法intializes当构造函数充满不必要的东西时,这是正常的事情。即使在像C#常规约定这样的键入程序语言中,也要添加一种Initialize方法来处理该问题。

这是一点静态的静态组合,可以为我工作

class ConstantThingy{
        static get NO_REENTER__INIT() {
            if(ConstantThingy._NO_REENTER__INIT== null){
                ConstantThingy._NO_REENTER__INIT = new ConstantThingy(false,true);
            }
            return ConstantThingy._NO_REENTER__INIT;
        }
}

在其他地方使用

var conf = ConstantThingy.NO_REENTER__INIT;
if(conf.init)...
本文地址:http://javascript.askforanswer.com/es6leibianliangtidai.html
文章标签: ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!