Câu hỏi Khai báo hàm trong CoffeeScript


Tôi nhận thấy rằng trong CoffeeScript, nếu tôi định nghĩa một hàm bằng cách sử dụng:

a = (c) -> c=1

Tôi chỉ có thể nhận được biểu thức hàm:

var a;
a = function(c) {
    return c = 1;
};

Nhưng, cá nhân tôi thường xuyên sử dụng khai báo chức năng,ví dụ:

function a(c) {
    return c = 1;
}

Tôi sử dụng hình thức đầu tiên, nhưng tôi tự hỏi nếu có một cách trong CoffeeScript tạo ra một tuyên bố chức năng. Nếu không có cách nào như vậy, tôi muốn biết tại sao CoffeeScript tránh làm điều này. Tôi không nghĩ JSLint sẽ báo lỗi khi khai báo, miễn là hàm được khai báo ở đầu phạm vi.


76
2017-07-01 13:42


gốc


Bạn có lý do chính đáng nào để muốn khai báo chức năng không? Nếu bạn sử dụng coffeescript bạn không nên quan tâm về định dạng của JS được biên dịch trừ khi nó bị hỏng / bị lỗi. - Raynos
Trong hầu hết các trường hợp, khai báo hàm và biểu thức hàm hoạt động theo cùng một cách, nhưng có sự khác biệt đôi chút giữa hai hàm. Ví dụ, developer.mozilla.org/en/JavaScript/Reference/… Vì vậy, trong một số trường hợp, chúng không bằng nhau. - Grace Shao
bạn đã liên kết tôi với một đoạn mã trong đó khai báo hàm là hành vi không xác định. Bạn có muốn sử dụng các khai báo hàm thay vì các biểu thức hàm để bạn có thể sự lạm dụng hành vi không xác định? - Raynos
Các khai báo hàm @Raynos có thể tốt đẹp cho các dấu vết ngăn xếp và gỡ lỗi khác, vì tên được gắn với hàm. Đó là lý do CoffeeScript sử dụng chúng cho classes. - Trevor Burnham
@TrevorBurnham Tôi có nghĩa là đó chỉ là một cải tiến nhỏ về độ khó gỡ lỗi js được biên dịch. Những gì bạn thực sự muốn là một trình gỡ lỗi có thể đọc coffeescript. - Raynos


Các câu trả lời:


CoffeeScript sử dụng các khai báo hàm (còn gọi là "các hàm được đặt tên") chỉ ở một nơi: class các định nghĩa. Ví dụ,

class Foo

biên dịch thành

var Foo;
Foo = (function() {
  function Foo() {}
  return Foo;
})();

Lý do CoffeeScript không sử dụng các khai báo hàm ở nơi khác, theo Câu hỏi thường gặp:

Đổ lỗi cho Microsoft cho cái này. Ban đầu tất cả các chức năng có thể có một tên hợp lý lấy cho nó đã được đưa ra một, nhưng IE phiên bản 8 và xuống có scoping vấn đề mà chức năng được đặt tên được coi là một tuyên bố và một biểu thức. Xem điều này để biết thêm thông tin.

Tóm lại: Việc sử dụng các khai báo hàm bất cẩn có thể dẫn đến sự mâu thuẫn giữa IE (trước-9) và các môi trường JS khác, vì vậy CoffeeScript tránh chúng.


60
2017-07-01 15:32



Anh ấy đang nói về vấn đề của IE với Biểu thức hàm được đặt tên (ví dụ: var a = function a() {};). Tuyên bố chức năng (ví dụ: function a() {}) không có sự không nhất quán giữa các trình duyệt - AngusC
Điều này sẽ hợp lý hơn nếu tôi không sử dụng CS trong trình duyệt ngay từ đầu. Bạn nên đặt niềm tin vào thư viện xử lý DOM để theo kịp các biến thể của trình duyệt và không dùng nữa nhưng khi điều bạn đang nói đến là mã nguồn thực sự, điều đó giống như sự phụ thuộc vào nguy cơ đôi. Hãy tưởng tượng đối phó với một cơ sở mã di sản 10 năm sau khi cộng đồng CS khô cạn và chuyển sang hiện tượng làm cho nó rê-chi-rê-ri-cho-tôi-tiếp theo. Khi tất cả mọi thứ bắt đầu phá vỡ và đó là vào bạn để tìm hiểu những gì đã không được chấp nhận và tìm ra những gì cần sửa trong trình phân tích CS. - Erik Reppen


Có, bạn có thể:

hello()

`function hello() {`
console.log 'hello'
dothings()
`}`

Bạn thoát khỏi JS tinh khiết thông qua backtick `

Lưu ý rằng bạn không thể thụt lề trên cơ thể chức năng của mình.

Chúc mừng


12
2018-03-25 00:38



Điều này không cho thấy nó đang được thực hiện trong coffeescript - chỉ rằng coffeescript cho phép thoát javascript. Ngoài ra đây là naaaasty! - Mr Wilde
Định nghĩa trước khi sử dụng khó chịu hơn xD - Zaid Daghestani
Ngoài ra, các khai báo hàm xuất hiện rất nhiều được tối ưu hóa trong các phiên bản sau của v8. - James M. Lay
Zalid - bạn da man! - avalanche1
lưu ý rằng bạn có thể viết function updateSettings() {; do -> dothings () } để cho phép thụt đầu dòng. github.com/jashkenas/coffeescript/issues/… - avalanche1


Một điều cần ghi nhớ với CoffeeScript là bạn luôn có thể quay lại JavaScript. Trong khi CoffeeScript không hỗ trợ các khai báo hàm được đặt tên, bạn luôn có thể quay trở lại JavaScript để làm điều đó.

http://jsbin.com/iSUFazA/11/edit

# http://jsbin.com/iSUFazA/11/edit
# You cannot call a variable function prior to declaring it!
# alert csAddNumbers(2,3) # bad!

# CoffeeScript function
csAddNumbers = (x,y) -> x+y

# You can call a named function prior to
# delcaring it
alert "Calling jsMultiplyNumbers: " + jsMultiplyNumbers(2,3) # ok!

# JavaScript named function
# Backticks FTW!
`function jsMultiplyNumbers(x,y) { return x * y; }`

Bạn cũng có thể viết một hàm lượng chất béo lớn trong CoffeeScript và sau đó chỉ cần sử dụng mẹo sau để JavaScript có thể gọi hàm khác:

# Coffeescript big function
csSomeBigFunction = (x,y) ->
   z = x + y
   z = z * x * y
   # do other stuff
   # keep doing other stuff

# Javascript named function wrapper
`function jsSomeBigFunction(x,y) { return csSomeBigFunction(x,y); }`

6
2017-10-27 18:47





Không, bạn không thể định nghĩa một hàm trong kịch bản lệnh cà phê và nó có thể tạo ra một khai báo hàm trong kịch bản lệnh cà phê

Ngay cả khi bạn chỉ viết

-> 123

JS được tạo ra sẽ được bao bọc trong các parens, do đó làm cho nó trở thành một biểu thức hàm

(function() {
  return 123;
});

Tôi đoán là điều này là bởi vì các khai báo hàm nhận được "hoisted" lên đầu phạm vi bao quanh mà sẽ phá vỡ luồng logic của nguồn coffeescript.


1
2017-10-13 18:18



Các cẩu là chính xác lý do tại sao tôi muốn sử dụng các khai báo chức năng! - ivanreese
CoffeeScript trong một ý nghĩa đã "hoist" bởi vì nó predeclares biến với var ở đầu phạm vi. Vì vậy, chức năng có thể tham khảo lẫn nhau và trật tự không quan trọng. - Evan Moran
@EvanMoran Đúng là CoffeeScript khai báo trước các biến, nhưng các hàm không được treo bởi vì biến vẫn không xác định cho đến khi biểu thức hàm. Do đó, bạn không thể sử dụng các hàm cho đến sau khi chúng được xác định. - jasonkarns


Mặc dù đây là bài đăng cũ hơn, tôi muốn thêm nội dung nào đó vào cuộc trò chuyện cho những người dùng Google trong tương lai.

OP là chính xác ở chỗ chúng ta không thể khai báo các hàm trong CoffeeScript thuần túy (không bao gồm ý tưởng sử dụng các dấu tick để thoát khỏi JS thuần túy bên trong tệp CoffeeScript).

Nhưng những gì chúng ta có thể làm là liên kết hàm với cửa sổ và về cơ bản kết thúc với một cái gì đó mà chúng ta có thể gọi như thể nó là một hàm được đặt tên. Tôi không nói điều này  một hàm được đặt tên, tôi đang cung cấp một cách để làm những gì tôi tưởng tượng OP muốn thực sự làm (gọi một hàm như foo (param) ở đâu đó trong mã) bằng cách sử dụng CoffeeScript thuần túy.

Đây là một ví dụ về một hàm được gắn vào cửa sổ trong coffeescript:

window.autocomplete_form = (e) ->
    autocomplete = undefined
    street_address_1 = $('#property_street_address_1')
    autocomplete = new google.maps.places.Autocomplete(street_address_1[0], {})
    google.maps.event.addListener autocomplete, "place_changed", ->
        place = autocomplete.getPlace()

        i = 0

        while i < place.address_components.length
            addr = place.address_components[i]
            st_num = addr.long_name if addr.types[0] is "street_number"
            st_name = addr.long_name if addr.types[0] is "route"

            $("#property_city").val addr.long_name if addr.types[0] is "locality"
            $("#property_state").val addr.short_name if addr.types[0] is "administrative_area_level_1"
            $("#property_county").val (addr.long_name).replace(new RegExp("\\bcounty\\b", "gi"), "").trim() if addr.types[0] is "administrative_area_level_2"
            $("#property_zip_code").val addr.long_name if addr.types[0] is "postal_code"
            i++

        if st_num isnt "" and (st_num?) and st_num isnt "undefined"
            street1 = st_num + " " + st_name
        else
            street1 = st_name

        street_address_1.blur()
        setTimeout (->
            street_address_1.val("").val street1
            return
            ), 10
        street_address_1.val street1
        return

Điều này đang sử dụng Google Địa điểm để trả lại thông tin địa chỉ để tự động điền biểu mẫu.

Vì vậy, chúng tôi có một phần trong một ứng dụng Rails đang được tải vào một trang. Điều này có nghĩa là DOM đã được tạo và nếu chúng ta gọi hàm ở trên trên tải trang ban đầu (trước khi cuộc gọi ajax hiển thị một phần), jQuery sẽ không nhìn thấy phần tử $ ('# property_street_address_1') (tin tưởng tôi - nó đã không ') t).

Vì vậy, chúng tôi cần phải trì hoãn google.maps.places.Autocomplete () cho đến sau khi phần tử có mặt trên trang.

Chúng ta có thể thực hiện điều này thông qua việc gọi lại Ajax khi tải thành công phần:

            url = "/proposal/"+property_id+"/getSectionProperty"
            $("#targ-"+target).load url, (response, status, xhr) ->
                if status is 'success'
                    console.log('Loading the autocomplete form...')
                    window.autocomplete_form()
                    return

            window.isSectionDirty = false

Vì vậy, ở đây, về cơ bản, chúng tôi đang làm điều tương tự như gọi foo ()


1
2017-10-09 16:34





Tại sao? Bởi vì khai báo chức năng là điều ác. Nhìn vào mã này

function a() {
        return 'a';
}

console.log(a());

function a() {
        return 'b';
}

console.log(a());

Điều gì sẽ được trên đầu ra?

b
b

Nếu chúng ta sử dụng chức năng độ nét

var a = function() {
        return 'a';
}

console.log(a());

a = function() {
        return 'b';
}

console.log(a());

đầu ra là:

a
b

1
2017-11-02 15:04



Không có gì xấu về khai báo hàm. Bạn chỉ cần hiểu cách khai báo biến và hàm được hoisted trong JS. Đọc thêm về biến cẩu và chức năng cẩu - Ben Harold
định nghĩa hàm là intitive hơn khai báo hàm. - Tomasz Jakub Rup


Thử cái này:

defineFct = (name, fct)->
  eval("var x = function #{name}() { return fct.call(this, arguments); }")
  return x

Bây giờ sau đây sẽ in "true":

foo = defineFct('foo', ()->'foo')
console.log(foo() == foo.name)

Tôi không thực sự sử dụng điều này, nhưng đôi khi muốn các chức năng cà phê có tên cho sự mẫn cảm.


0
2017-10-21 01:05