2012-02-20 28 views
9

Tôi đã chơi xung quanh với khái niệm về enums/hằng số trong coffeescript (http://coffeescript.org/) và đã đưa ra đoạn mã sau có vẻ OK. Làm thế nào tôi có thể nâng cao điều này để thậm chí tốt hơn cho một cái gì đó mà một enum sẽ phù hợp? google tìm kiếm cho điều này chưa tiết lộ sự hài lòng.coffeescript và enum values ​​

class SomeService 

    @SomeEnumValue : 400 
    @SomeOtherValue : 402 

    someFunc: -> 
    SomeService.SomeEnumValue 

ok = new SomeService() 
alert ok.someFunc() 

if (ok.someFunc() == SomeService.SomeEnumValue) then alert ' some enum value' 
+2

Chính xác là bạn đang tìm kiếm điều gì? JavaScript không có hằng số và enums của nó chỉ là băm, vì vậy bất cứ điều gì bạn đưa ra trong CoffeeScript với sẽ được định dạng tương tự. Đối với enums CS, tôi chỉ xây dựng một băm như vậy: @Colors = Red: 1, Blue: 2 – egoodberry

+0

Tôi muốn chắc chắn rằng tôi đã không bỏ lỡ một cái gì đó. Cảm ơn! – finneycanhelp

Trả lời

19

Toàn bộ khái niệm về enum chỉ là vô dụng trong các ngôn ngữ động như là tuple, gõ danh sách, bản đồ và rất nhiều thứ khác, và Javascript (Coffeescript) là năng động. Trong khi làm việc với ngôn ngữ năng động, bạn chỉ cần quên về kiểm tra kiểu và sử dụng các cấu trúc tổng quát hiện có hơn để giải quyết vấn đề của bạn. Sử dụng mảng thay vì danh sách và bộ dữ liệu, sử dụng đối tượng thay vì bản đồ và enums và chỉ tin tưởng loại giá trị được chuyển đến hàm, nhưng kiểm tra đơn vị mã của bạn. Đối với tốt hơn hoặc tệ hơn (cho IMO tồi tệ hơn) đó chỉ là cách một công việc được thực hiện ở đây.

Trong trường hợp của bạn tôi sẽ khuyên bạn nên chỉ lưu trữ giá trị của bạn trong một đối tượng singleton, như vậy:

HTTPStatusCodes = 
    ok : 200 
    badRequest : 400 
    unauthorized : 401 

và truy cập vào nó như vậy:

class SomeService 
    okCode: -> 
    HTTPStatusCodes.ok 
    failureCodes: -> 
    code for key, code of HTTPStatusCodes when code >= 400 
+3

Làm thế nào các tuples và bản đồ vô dụng? – Darthfett

+6

@ Darthfett Đừng bỏ các từ của tôi ra khỏi ngữ cảnh. Tôi nói rằng họ vô dụng ** bằng ngôn ngữ năng động **. Và đó là như vậy bởi vì không có giới hạn kiểu trong ngôn ngữ động, mà, ví dụ, xóa một ranh giới giữa tuple và mảng. Trong ngôn ngữ tĩnh, các cấu trúc khác như thế chỉ là không thể thiếu. –

+4

Tôi thích giải pháp của bạn và nó hoàn hảo cho tôi. Tôi nhận được quan điểm của bạn về các emum là vô ích trong các ngôn ngữ động về hạn chế loại nhưng về khả năng đọc mã chúng hoàn toàn cần thiết. Giải pháp của bạn cung cấp một cách hoàn hảo. –

4

tôi rất không đồng ý với tuyên bố rằng Enums là vô ích do tính chất động của Javascript hoặc Enums là ít băm được tôn vinh hơn.

Trích dẫn Wikipedia: "Biến đã được khai báo là có loại liệt kê có thể được gán bất kỳ điều tra nào làm giá trị." Và chỉ những điều tra viên mới có thể làm giá trị.

Coffeescript có thể dễ dàng và cú pháp làm hài lòng thi đua một Enum. Bao gồm xử lý lỗi trên các giá trị điều tra không hợp lệ (mặc dù chỉ trong thời gian chạy)

Tôi đã tạo một ví dụ chủ yếu là chức năng và sử dụng gọi lại vô danh chức năng như một phương tiện giao - về cơ bản thay thế toán tử gán "=" cho Quản trị viên chức năng Coffeescripts "->". Nó làm cho đoạn mã dày đặc nhất trong cuốn sách của tôi. Tuy nhiên một cách tiếp cận dựa trên lớp học hơn là chắc chắn có thể.

#define enumeration 
httpcodes = Enum 
    ok: 200 
    badRequest: 400 
    unauthorized: 401 
    server_error: 500 

#set enum variables with some default state 
chrome = httpcodes -> @server_error 
firefox = httpcodes -> @server_error 
safari = httpcodes -> @server_error 

console.log "httpcodes.ok:" + httpcodes.ok 

#change enum value 
chrome -> @ok 
firefox -> @badRequest 
safari -> @unauthorized 

console.log "chrome:" + chrome -> 
console.log "firefox:" + firefox -> 
console.log "safari:" + safari -> 

console.log "(chrome ->) == httpcodes.ok:" + ((chrome ->) == httpcodes.ok) 

#set an invalid value 
try 
    safari -> 999 
catch err 
    console.log err 
    console.log "safari:" + safari -> 

Và đây là đoạn code để tạo ra một Enum (bạn cần phải đặt này trên đầu của mã nếu bạn muốn chạy nó. Chỉ muốn hiển thị các mã sử dụng trước khi mã thực hiện

Enum = (enumeration)-> 
    check = (value)-> 
     newval = null 
     for key, val of enumeration 
      if val == value 
       newval = value 
       break 
     if !newval 
      throw "Invalid Enum Value: #{value}" 

    result = (init)-> 
     state = init.call(enumeration) 
     check state 
     (callback)-> 
       value = callback.call(enumeration) 
       if value == null or value == undefined 
        return state 
       else 
        check value 
        state = value 

     for key, value of enumeration 
      result[key] = value 

     result 

Rõ ràng sẽ đẹp hơn nhiều nếu Coffeescript có macro cú pháp. Vì vậy, chúng ta có thể viết

Enum httpcodes 
    ok: 200 
    badrequest: 400 

chrome = httpcodes 'ok 
#or 
chrome := 'ok 
+8

Tôi xin lỗi, nhưng đây chỉ là một mớ hỗn độn. 1. Nó không phải enum bạn đang làm ở đây nhưng một đối tượng với một nhà nước chuyển đổi và nó không có gì để làm với wikipedia quote của bạn. 2. Cả đối tượng và các biến bạn gán cho nó vẫn không được bảo vệ khỏi việc được gán với các giá trị của bất kỳ loại nào khác, bởi vì, một lần nữa, JavaScript là động. 3. Toàn bộ mặt tiền này chắc chắn sẽ làm giảm hiệu suất. 4. Các mã nói cho chính nó về cách phức tạp và quản lý nó được. Vì vậy, tất cả những thương vong cho những gì chính xác lợi ích? Tôi xin lỗi, nhưng về cơ bản nó chỉ là một sự quá mức mà không có mục đích thực tế. –

+1

trên 1) một enum khác với một đối tượng với "trạng thái" chuyển đổi được xác định trước là gì? trên 2) nó sẽ rất dễ dàng để mở rộng này để tạo ra một tài sản trên bất kỳ máy chủ thông qua 'Object.defineProperty' mà bạn không thể ghi đè lên, trên 3) có nó sẽ chậm hơn. Nhưng nếu bạn không thể đủ khả năng một hoặc hai indirections thông qua các cuộc gọi chức năng - bạn có lẽ không nên sử dụng một môi trường javascript.trên 4) Tôi thấy 30 LOC khá dễ quản lý. Sự phức tạp là kết quả của phương pháp "chức năng" và cách tiếp cận đó một lần nữa là kết quả của việc cố gắng càng dày đặc càng tốt. Nhưng anyways - YMMY _ u không thích nó? không sử dụng nó. – robkuz

+2

1. Enum là loại có tập hợp các giá trị có thể bị hạn chế. Nó không phải là một đối tượng, giá trị của nó là các đối tượng của nó. 3. Xử lý hiệu suất là "không phải là một vấn đề" trong bất kỳ môi trường nào chỉ có thể nói về trình độ của nhà phát triển. Và nó không chỉ là về những kẻ vô đạo trong trường hợp của bạn, mà là những cuộc tấn công không cần thiết. 4. Ồ không, bạn không chỉ gọi một chức năng giải pháp dựa trên trạng thái có thể thay đổi được) Vui lòng không nói đến những điều bạn rõ ràng không biết gì về chỉ vì lợi ích của cuộc tranh cãi. –

5

Tôi biết tôi là muộn để đảng, nhưng đối với hậu thế con xin dâng lên một "coffeethonic" giải pháp (theo tinh thần-gõ ít hơn) :

[ a, b, c ] = [1..3] 
2
Colors = Object.freeze({ 
    RED: 'red' 
    GREEN: 'green' 
    BLUE: 'blue' 
}) 
console.log Colors.RED 
# red 

giá trị là hằng số (bạn không thể thay đổi chúng):

01.
Colors.RED = 'black' 
console.log Colors.RED 
# red 
1

Tôi bắt đầu một ngày tự hỏi về enums trong coffeescript và kết thúc bằng giải pháp I published on github (available in npm, bower, meteor too). Tôi đã cố gắng để phát triển các enums giống như java, nhưng thậm chí còn linh hoạt hơn cho sự pha trộn giữa thừa kế nguyên mẫu và coffeescript thừa kế cổ điển dựa vào.

Sau đây là cách nó sẽ phù hợp với mã của bạn:

class SomeService 
    someFunc: -> SomeService.SomeEnumValue 
    #A cool hack, but it must be the last class statement. 
    #Your class will now inherit this enumeration's properties. 
    #If you find this too hacky, you can always have a public static 
    #states class property instead. 
    @__proto__:new Enumeration('SomeService',{ 
      SomeEnumValue :400 
      SomeOtherValue:402 
     }) 

ok = new SomeService() 

alert ok.someFunc().id() #shows 400 

if (ok.someFunc() is SomeService.SomeEnumValue) then alert ' some enum value' 

Nhưng điều tuyệt vời trong việc thực hiện này, là enum của bạn có thể có lĩnh vực cụ thể, và kế thừa từ một nguyên mẫu (argument constructor 3d) mặc dù độc đáo được đảm bảo . Điều đó cho phép bạn refactor mã của bạn và di chuyển một số logic bên trong những chức năng. Bây giờ chúng ta hãy hỏi giá trị enum này để cho chúng ta biết điều gì đó khi anh ta cần, bằng cách định nghĩa một hàm tell.

class SomeService 
    someFunc: -> SomeService.SomeEnumValue 
    #A cool hack, but it must be the last class statement. 
    #Your class will now inherit this enumeration's properties. 
    #If you find this too hacky, you can always have a public static 
    #states class property instead. 
    @__proto__:new Enumeration('SomeService', 
       SomeEnumValue : { _id:400, text: ' some enum value' } 
       SomeOtherValue: { _id:402, text: null } 
     , tell:->if @text? then alert @text) 

ok = new SomeService() 

alert ok.someFunc().id() #shows 400 

ok.someFunc().tell() 

Hy vọng điều này sẽ giúp ai đó, bạn có thể kiểm tra địa chỉ github để xem xét triển khai và một số tài liệu chi tiết hơn tôi đã viết.