Các lựa chọn thay thế lớp ES6


492

Hiện tại trong ES5, nhiều người trong chúng ta đang sử dụng mẫu sau trong các khung để tạo các lớp và biến lớp, đó là comfy:

// ES 5
FrameWork.Class({

    variable: 'string',
    variable2: true,

    init: function(){

    },

    addItem: function(){

    }

});

Trong ES6, bạn có thể tạo các lớp nguyên bản, nhưng không có tùy chọn để có các biến lớp:

// ES6
class MyClass {
    const MY_CONST = 'string'; // <-- this is not possible in ES6
    constructor(){
        this.MY_CONST;
    }
}

Đáng buồn thay, ở trên sẽ không hoạt động, vì các lớp chỉ có thể chứa các phương thức.

Tôi hiểu rằng tôi có thể this.myVar = truetrong trò chơi constructornhưng tôi không muốn 'rác' nhà xây dựng của mình, đặc biệt là khi tôi có 20-30 + params cho một lớp lớn hơn.

Tôi đã nghĩ ra nhiều cách để xử lý vấn đề này, nhưng vẫn chưa tìm được cách nào tốt. (Ví dụ: tạo một ClassConfighandler, và vượt qua một parameterđối tượng, đó là tuyên bố tách biệt khỏi lớp Sau đó xử lý sẽ gắn vào lớp tôi đã suy nghĩ về.. WeakMapsCũng để tích hợp, bằng cách nào đó.)

Những loại ý tưởng bạn sẽ phải xử lý tình huống này?


1
vấn đề chính của bạn là bạn sẽ có sự lặp lại this.member = memberở nhà xây dựng của mình với 20-30 tham số?
Θεόφιλος Μουρατίδης

1
Bạn không thể sử dụng public variable2 = truedưới lớp học? Điều này sẽ xác định nó trên nguyên mẫu.

14
@ Θεόφς: Có, và tôi cũng muốn sử dụng hàm tạo của mình cho các thủ tục khởi tạo và không cho khai báo biến.
Wintercount

@derylius: Đây là vấn đề chính, nó không có tính năng như vậy. Ngay cả việc sử dụng công khai / riêng tư vẫn chưa được quyết định trong dự thảo ES6. Cho nó một spin thử nghiệm: es6fiddle.net
wintercounter

Theo mới nhất, nó có chức năng này: wiki.ecmascript.org/doku.php?id=harmony

Câu trả lời:


515

Cập nhật 2018:

Hiện tại đã có một đề xuất giai đoạn 3 - tôi mong muốn làm cho câu trả lời này trở nên lỗi thời trong một vài tháng.

Trong khi đó, bất cứ ai sử dụng TypeScript hoặc babel đều có thể sử dụng cú pháp:

varName = value

Bên trong một thân khai báo / biểu thức lớp và nó sẽ định nghĩa một biến. Hy vọng trong một vài tháng / tuần tôi sẽ có thể đăng cập nhật.

Cập nhật: Chrome 74 hiện đã xuất xưởng với cú pháp này hoạt động.


Các ghi chú trong wiki ES cho đề xuất trong ES6 ( các lớp tối thiểu tối đa ) lưu ý:

(Cố ý) không có cách khai báo trực tiếp để định nghĩa các thuộc tính dữ liệu nguyên mẫu (trừ các phương thức) hoặc thuộc tính thể hiện

Các thuộc tính lớp và thuộc tính dữ liệu nguyên mẫu cần được tạo bên ngoài khai báo.

Các thuộc tính được chỉ định trong một định nghĩa lớp được gán các thuộc tính giống như khi chúng xuất hiện trong một đối tượng bằng chữ.

Điều này có nghĩa là những gì bạn yêu cầu đã được xem xét và quyết định rõ ràng chống lại.

nhưng tại sao?

Câu hỏi hay. Những người tốt của TC39 muốn khai báo lớp để khai báo và định nghĩa các khả năng của một lớp. Không phải thành viên của nó. Một khai báo lớp ES6 xác định hợp đồng của nó cho người dùng của nó.

Hãy nhớ rằng, một định nghĩa lớp định nghĩa các phương thức nguyên mẫu - xác định các biến trên nguyên mẫu thường không phải là thứ bạn làm. Tất nhiên bạn có thể sử dụng:

constructor(){
    this.foo = bar
}

Trong các nhà xây dựng như bạn đề nghị. Cũng xem tóm tắt của sự đồng thuận .

ES7 và hơn thế nữa

Một đề xuất mới cho ES7 đang được thực hiện trên đó cho phép các biến đối tượng ngắn gọn hơn thông qua các khai báo và biểu thức lớp - https://esdiscuss.org/topic/es7-property-initialulators


4
@wintercount điều quan trọng cần rút ra từ nó là cho phép xác định các thuộc tính sẽ định nghĩa chúng trên nguyên mẫu giống như các phương thức chứ không phải trên mỗi trường hợp. Các lớp tối thiểu vẫn còn ở mức kế thừa nguyên mẫu rất cốt lõi của nó. Những gì bạn thực sự muốn làm trong trường hợp của bạn là chia sẻ cấu trúc và chỉ định các thành viên cho mỗi trường hợp. Đây đơn giản không phải là những gì các lớp trong ES6 nhắm đến - chức năng chia sẻ. Vì vậy, có, để chia sẻ cấu trúc, bạn phải tuân theo cú pháp cũ. Cho đến ít nhất ES7 :)
Benjamin Gruenbaum

5
Bạn có thể muốn đề cập đến statictài sản
Bergi

8
Rất tiếc, rắm não. Tôi quên rằng staticchỉ hoạt động cho các phương pháp là tốt.
Bergi

637
Có lẽ những người tốt ở TC39 nên đặt tên cho khái niệm này là "class" nếu họ không muốn nó hoạt động giống như phần còn lại của thế giới lập trình mong đợi từ một thứ gọi là "class".
Alex

7
Xem thêm đề xuất "Trường lớp & Thuộc tính tĩnh" (đã được triển khai trong Babel : github.com/jeffmo/es-
Matt Browne

127

Chỉ cần thêm vào câu trả lời của Benjamin - có thể có các biến lớp, nhưng bạn sẽ không sử dụng prototypeđể đặt chúng.

Đối với một biến lớp thực sự, bạn muốn làm một cái gì đó như sau:

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

Từ trong một phương thức lớp, biến đó có thể được truy cập dưới dạng this.constructor.foo(hoặc MyClass.foo).

Các thuộc tính lớp này thường không thể truy cập được từ đối tượng lớp. tức là MyClass.foocho 'bar'nhưng new MyClass().fooundefined

Nếu bạn cũng muốn có quyền truy cập vào biến lớp của mình từ một thể hiện, bạn sẽ phải xác định thêm một getter:

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

MyClass.foo = 'bar';

Tôi chỉ thử nghiệm điều này với Traceur, nhưng tôi tin rằng nó sẽ hoạt động tương tự trong một triển khai tiêu chuẩn.

JavaScript không thực sự có các lớp . Ngay cả với ES6, chúng tôi đang xem xét một ngôn ngữ dựa trên đối tượng hoặc nguyên mẫu thay vì ngôn ngữ dựa trên lớp. Trong bất kỳ function X () {}, X.prototype.constructorđiểm trở lại X. Khi newtoán tử được sử dụng trên X, một đối tượng mới được tạo kế thừa X.prototype. Bất kỳ thuộc tính không xác định nào trong đối tượng mới (bao gồm constructor) được tra cứu từ đó. Chúng ta có thể nghĩ về điều này như tạo các thuộc tính đối tượng và lớp.


29

Babel hỗ trợ các biến lớp trong ESNext, kiểm tra ví dụ này :

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'

1
Bạn có thể biến thanh thành một biến lớp riêng bằng cách giả vờ nó với "#" như thế này: #bar = 2;
Lonnie hay nhất

26

Trong ví dụ của bạn:

class MyClass {
    const MY_CONST = 'string';
    constructor(){
        this.MY_CONST;
    }
}

Vì MY_CONST là nguyên thủy https://developer.mozilla.org/en-US/docs/Glossary/Primitive chúng tôi chỉ có thể làm:

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

Nhưng nếu MY_CONSTlà kiểu tham chiếu như static get MY_CONST() {return ['string'];}đầu ra cảnh báo là chuỗi, sai . Trong trường hợp như vậy, deletetoán tử có thể thực hiện thủ thuật:

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

Và cuối cùng cho biến lớp không 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

5
Vui lòng tránh các deletenhà điều hành, nếu một mình vì lý do hiệu suất. Những gì bạn thực sự muốn ở đây là Object.defineProperty.
Bergi

@shinzou Mình cũng nghĩ như vậy. Tuy nhiên, không nhất thiết là lỗi của OP; đó thực sự là ngôn ngữ thiếu các cơ chế phù hợp để thể hiện dữ liệu theo cách phản ánh các mối quan hệ trong thế giới thực của nó.
dùng1974458

17

Vì vấn đề của bạn chủ yếu là về phong cách (không muốn lấp đầy các hàm tạo bằng một loạt các khai báo), nó cũng có thể được giải quyết theo kiểu cách.

Theo cách tôi xem, nhiều ngôn ngữ dựa trên lớp có hàm tạo là một hàm được đặt tên theo chính tên lớp. Về mặt phong cách, chúng ta có thể sử dụng điều đó để tạo ra một lớp ES6 mà theo phong cách vẫn có ý nghĩa nhưng không nhóm các hành động điển hình diễn ra trong hàm tạo với tất cả các khai báo thuộc tính mà chúng ta đang thực hiện. Chúng ta chỉ đơn giản sử dụng hàm tạo JS thực tế làm "vùng khai báo", sau đó tạo một hàm có tên lớp mà chúng ta coi là vùng "công cụ xây dựng khác", gọi nó là ở cuối của hàm tạo thực sự.

"Sử dụng nghiêm ngặt";

lớp MyClass
{
    // chỉ khai báo các thuộc tính của bạn và sau đó gọi this.ClassName (); từ đây
    constructor(){
        this .prop1 = 'blah 1';
        this .prop2 = 'blah 2';
        this .prop3 = 'blah 3';
        this.MyClass ();
    }

    // tất cả các loại công cụ "hàm tạo" khác, không còn bị xáo trộn với các khai báo
    Lớp học của tôi() {
        làm bất cứ điều gì();
    }
}

Cả hai sẽ được gọi là thể hiện mới được xây dựng.

Sắp xếp giống như có 2 hàm tạo trong đó bạn tách riêng các khai báo và các hành động hàm tạo khác mà bạn muốn thực hiện, và theo kiểu cách làm cho nó không quá khó hiểu đó là những gì đang diễn ra.

Tôi thấy đó là một phong cách hay để sử dụng khi xử lý nhiều tuyên bố và / hoặc rất nhiều hành động cần phải xảy ra khi khởi tạo và muốn giữ hai ý tưởng khác biệt với nhau.


LƯU Ý : Tôi rất cố tình không sử dụng các ý tưởng thành ngữ điển hình về "khởi tạo" (như một phương pháp init()hoặc initialize()phương pháp) bởi vì những ý tưởng đó thường được sử dụng khác nhau. Có một sự khác biệt được cho là giữa ý tưởng xây dựng và khởi tạo. Làm việc với các nhà xây dựng, mọi người biết rằng họ được gọi tự động như một phần của việc khởi tạo. Nhìn thấy một initphương pháp, nhiều người sẽ giả định mà không cần nhìn thoáng qua rằng họ cần phải làm gì đó theo hình thức var mc = MyClass(); mc.init();, bởi vì đó là cách bạn thường khởi tạo. Tôi không cố gắng thêm quy trình khởi tạo cho người dùng của lớp, tôi đang cố thêm vào quy trình xây dựng của chính lớp đó.

Mặc dù một số người có thể thực hiện gấp đôi trong giây lát, nhưng đó thực sự là một phần của vấn đề: nó nói với họ rằng ý định là một phần của việc xây dựng, ngay cả khi điều đó khiến họ thực hiện một chút hai lần và đi "không phải vậy Làm thế nào các nhà xây dựng ES6 hoạt động "và mất một giây nhìn vào nhà xây dựng thực tế để nói" ồ, họ gọi nó ở phía dưới, tôi thấy ", điều đó tốt hơn nhiều so với việc KHÔNG truyền đạt ý định đó (hoặc truyền đạt không chính xác) và có thể nhận được rất nhiều mọi người sử dụng sai, cố gắng khởi tạo nó từ bên ngoài và rác. Đó là rất nhiều chủ ý cho mẫu tôi đề nghị.


Đối với những người không muốn theo mô hình đó, hoàn toàn ngược lại cũng có thể hoạt động. Farm khai báo ra chức năng khác lúc đầu. Có thể đặt tên cho nó là "tài sản" hoặc "công cộng" hoặc một cái gì đó. Sau đó đặt phần còn lại của công cụ vào hàm tạo bình thường.

"Sử dụng nghiêm ngặt";

lớp MyClass
{
    tính chất() {
        this .prop1 = 'blah 1';
        this .prop2 = 'blah 2';
        this .prop3 = 'blah 3';
    }

    constructor() {
        this.properations ();
        làm bất cứ điều gì();
    }
}

Lưu ý rằng phương thức thứ hai này có thể trông sạch hơn nhưng nó cũng có một vấn đề cố hữu khi propertiesbị ghi đè khi một lớp sử dụng phương thức này mở rộng phương thức khác. Bạn sẽ phải đặt nhiều tên độc đáo hơn propertiesđể tránh điều đó. Phương thức đầu tiên của tôi không gặp vấn đề này bởi vì một nửa hàm tạo của nó được đặt tên duy nhất theo lớp.


1
Vui lòng không sử dụng một phương thức nguyên mẫu được đặt tên theo chính lớp đó. Đó không phải là thành ngữ trong JS, đừng cố làm cho nó giống như một ngôn ngữ khác. Nếu bạn thực sự muốn sử dụng phương pháp này, tên chính tắc cho phương thức này là init.
Bergi

1
@Bergi - initlà một mẫu được sử dụng thường xuyên và thường được gọi từ bên ngoài lớp khi người dùng bên ngoài muốn khởi tạo, tức là var b = new Thing(); b.init();. Đây là một lựa chọn phong cách 100% mà tôi muốn truyền đạt rằng đó là chức năng thứ 2 được gọi tự động bằng cách tận dụng các mẫu được tìm thấy trong các ngôn ngữ khác. Ít có khả năng ai đó sẽ nhìn vào điều này và cho rằng họ cần gọi MyClassphương thức từ bên ngoài, nhiều khả năng họ sẽ nhận ra ý định là phương pháp thứ 2 đang hoạt động trong xây dựng (tức là được gọi là ngay lập tức).
Jimbo Jonny

Hừm, tôi có thể nhận ra rằng bằng cách nhìn vào hàm tạo, nhưng không phải từ tên phương thức MyClass.
Bergi

1
@Bergi - Lấy một mẫu từ ngôn ngữ khác và áp dụng nó vào JS theo cách không phải là kỹ thuật đang xảy ra, nhưng vẫn hoạt động không hoàn toàn không có tiền lệ. Bạn không thể nói với tôi rằng không ai nhận thấy rằng $myvarcách tiêu chuẩn để đề cập đến các biến có ý định giữ các đối tượng jQuery không thuận tiện tương tự như mô hình có $ ở đầu các biến mà rất nhiều lập trình viên PHP đã sử dụng. Chỉ có một hàm ý nhỏ rằng "vâng, nó không giống nhau chính xác ... nhưng nhìn ... nó vẫn là một biến vì đó là cách biến được thực hiện trong một số ngôn ngữ!" giúp.
Jimbo Jonny

1
Tôi thích tùy chọn cuối cùng của bạn với properties()chức năng. Tuy nhiên, mọi thứ trở nên phức tạp hơn một chút khi mở rộng các lớp vì vậy tôi sẽ đề nghị rằng nếu bạn sử dụng một properties()hàm trong tất cả các lớp để khai báo các thuộc tính lớp mà bạn đặt tiền tố tên phương thức với tên lớp (IE: MyClassProperties()để tránh vô tình ghi đè chức năng gọi trong các lớp con. Ngoài ra, hãy nhớ rằng bất kỳ lệnh gọi nào super()phải được khai báo trước trong hàm tạo của lớp.
TheDarkIn1978

14

Cách oldschool thì sao?

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);

Trong constructor, bạn chỉ đề cập đến các vars phải được tính toán. Tôi thích kế thừa nguyên mẫu cho tính năng này - nó có thể giúp tiết kiệm rất nhiều bộ nhớ (trong trường hợp nếu có nhiều vars không bao giờ được gán).


4
Điều này không tiết kiệm bộ nhớ và nó chỉ làm cho hiệu suất kém hơn nhiều so với việc bạn đã khai báo chúng trong hàm tạo. codereview.stackexchange.com/a/28360/9258
Esailija

2
Ngoài ra, điều này đánh bại mục đích sử dụng các lớp ES6 ở nơi đầu tiên. Vì thế, dường như khó có thể sử dụng các lớp ES6 như các lớp oop thực sự, điều này có phần đáng thất vọng ...
Kokodoko

4
@Kokodoko oop thực - ý bạn là, ví dụ như trong Java? Tôi đồng ý, tôi đã nhận thấy rằng rất nhiều người tức giận với JS vì họ cố gắng sử dụng nó như Java, giống như họ đã quen, bởi vì cú pháp JS trông giống nhau và họ cho rằng nó hoạt động theo cùng một cách ... Nhưng từ bên trong, nó là khá khác nhau, như chúng ta biết.
zarkone

2
Nó không chỉ là về cú pháp ngôn ngữ mặc dù. Triết lý OOP cho vay khá tốt để lập trình nói chung - đặc biệt là khi tạo ứng dụng và trò chơi. Theo truyền thống, JS đã được triển khai trong việc xây dựng các trang web khá khác biệt. Bằng cách nào đó, hai cách tiếp cận này cần phải đi cùng nhau, vì web cũng đang trở nên nhiều hơn về các ứng dụng.
Kokodoko

1
@Kokodoko Chỉ vì đó là một OOP khác không có nghĩa là nó không phải là OOP. Nguyên mẫu là một cách tiếp cận OOP 100% giá trị; không ai sẽ gọi Self là "non-OOP" bởi vì nó sử dụng các nguyên mẫu. Không khớp với mô hình OOP khác có nghĩa là: nó khác.
Dave Newton

13

Như Benjamin đã nói trong câu trả lời của mình, TC39 đã quyết định rõ ràng không bao gồm tính năng này ít nhất là cho ES2015. Tuy nhiên, sự đồng thuận dường như là họ sẽ thêm nó vào ES2016.

Cú pháp chưa được quyết định, nhưng có một đề xuất sơ bộ cho ES2016 sẽ cho phép bạn khai báo các thuộc tính tĩnh trên một lớp.

Nhờ vào sự kỳ diệu của babel, bạn có thể sử dụng nó ngay hôm nay. Cho phép chuyển đổi các thuộc tính lớp theo các hướng dẫn này và bạn sẽ ổn. Đây là một ví dụ về cú pháp:

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

Đề xuất này ở trạng thái rất sớm, vì vậy hãy chuẩn bị tinh chỉnh cú pháp của bạn khi thời gian trôi qua.


Vâng, đó không phải là ES6. Trừ khi bạn biết nó là gì, bạn không nên sử dụng nó.
Bergi

10

[Chủ đề dài, không chắc chắn nếu nó đã được liệt kê dưới dạng tùy chọn ...].
Một thay thế đơn giản cho chỉ các phần tử , sẽ được xác định const bên ngoài lớp. Điều này sẽ chỉ có thể truy cập từ chính mô-đun, trừ khi đi kèm với một getter.
Cách prototypenày không xả rác và bạn có được 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);
    }
}

Điều gì xảy ra nếu bạn a) sử dụng varthay vì const2) sử dụng nhiều phiên bản của lớp này? Sau đó, các biến bên ngoài sẽ được thay đổi theo từng phiên bản của lớp
nick carraway

1
điểm không thành công @nickcarraway, đề nghị của tôi chỉ dành cho const, không phải là câu hỏi có tiêu đề.
Hertzel Guinness

6

ES7 cú pháp thành viên lớp:

ES7có một giải pháp để 'gửi rác' chức năng xây dựng của bạn. Đây là một ví dụ:

class Car {
  
  wheels = 4;
  weight = 100;

}

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

Ví dụ trên sẽ có nội dung như sau ES6:

class Car {

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

}

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

Lưu ý khi sử dụng cú pháp này có thể không được hỗ trợ bởi tất cả các trình duyệt và có thể phải được phiên mã phiên bản trước đó của JS.

Tiền thưởng: một nhà máy sản xuất đối tượng:

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);


3
Bạn đã hoàn thành các biến thể hiện, không phải biến lớp.
Tjad Clark

5

Bạn có thể bắt chước hành vi của lớp es6 ... và sử dụng các biến lớp của bạn :)

Nhìn mẹ ... không có lớp!

// 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);

Tôi đưa nó lên GitHub


0

Cách tôi giải quyết điều này, đó là một tùy chọn khác (nếu bạn có sẵn jQuery), là Xác định các trường trong một đối tượng trường học cũ và sau đó mở rộng lớp với đối tượng đó. Tôi cũng không muốn tiêu hóa các nhà xây dựng với các bài tập, đây dường như là một giải pháp gọn gàng.

function MyClassFields(){
    this.createdAt = new Date();
}

MyClassFields.prototype = {
    id : '',
    type : '',
    title : '',
    createdAt : null,
};

class MyClass {
    constructor() {
        $.extend(this,new MyClassFields());
    }
};

- Cập nhật sau bình luận của Bergi.

Không có phiên bản JQuery:

class SavedSearch  {
    constructor() {
        Object.assign(this,{
            id : '',
            type : '',
            title : '',
            createdAt: new Date(),
        });

    }
}

Bạn vẫn kết thúc với hàm tạo 'béo', nhưng ít nhất là tất cả trong một lớp và được chỉ định trong một lần nhấn.

EDIT # 2: Bây giờ tôi đã đi vòng tròn đầy đủ và hiện đang gán các giá trị trong hàm tạo, vd

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

Tại sao? Thực sự đơn giản, bằng cách sử dụng ở trên cộng với một số nhận xét về JSdoc, PHPStorm đã có thể thực hiện hoàn thành mã trên các thuộc tính. Chỉ định tất cả các vars trong một lần truy cập là tốt, nhưng việc không thể mã hóa hoàn thành các thuộc tính, imo, không xứng đáng với lợi ích hiệu năng (gần như chắc chắn rất nhỏ).


2
Nếu bạn có thể làm classcú pháp, bạn cũng có thể làm Object.assign. Không cần jQuery.
Bergi

Tôi không thấy bất kỳ điểm nào để tạo MyClassFieldsmột hàm tạo - nó không có bất kỳ phương thức nào. Bạn có thể giải thích lý do tại sao bạn làm điều này (thay vì, nói, một hàm nhà máy đơn giản trả về một đối tượng theo nghĩa đen)?
Bergi

@Bergi - Có lẽ là ép buộc thói quen chứ không phải bất cứ điều gì khác, phải trung thực. Cũng có cuộc gọi hay về Object.assign - không biết về điều đó!
Steve Childs

0

Chà, bạn có thể khai báo các biến bên trong Trình xây dựng.

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

var foo = new Foo()

foo.method()

1
Bạn sẽ cần tạo một thể hiện của lớp này để sử dụng biến này. Các hàm tĩnh không thể truy cập vào biến đó
Aditya

0

Tuy nhiên, bạn không thể khai báo bất kỳ lớp nào như trong các ngôn ngữ lập trình khác. Nhưng bạn có thể tạo nhiều biến lớp. Nhưng vấn đề là phạm vi của đối tượng lớp. Theo tôi, cách tốt nhất để lập trình OOP trong ES6 Javascript: -

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
   }
}

-1

Đây là một chút kết hợp hackish tĩnh và có được công việc cho tôi

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;
        }
}

nơi khác sử dụng

var conf = ConstantThingy.NO_REENTER__INIT;
if(conf.init)...

7
Tôi muốn giới thiệu singleton_instancenhư một tên tài sản để mọi người hiểu bạn đang làm gì ở đây.
Bergi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.