2013-08-28 45 views
9

Thời gian vui vẻ của JavaScript đất vui vẻCó tương đương với Ruby cho Function.prototype.bind của JavaScript không?

// make a method 
var happy = function(a, b, c) { 
    console.log(a, b, c); 
}; 

// store method to variable 
var b = happy; 

// bind a context and some arguments 
b.bind(happy, 1, 2, 3); 

// call the method without additional arguments 
b(); 

Đầu ra. Yay!

1 2 3 

Trong Ruby

# make a method 
def sad a, b, c 
    puts a, b, c 
end 

# store method to variable 
b = method(:sad) 

# i need some way to bind args now 
# (this line is an example of what i need) 
b.bind(1, 2, 3) 

# call the method without passing additional args 
b.call 

đầu ra mong muốn

1, 2, 3 

Đối với những gì nó có giá trị, tôi biết JavaScript có thể thay đổi bối cảnh của các ràng buộc với đối số đầu tiên được chuyển đến .bind. Trong Ruby, tôi sẽ vui vẻ 99% ngay cả khi tôi không thể thay đổi bối cảnh. Tôi chủ yếu chỉ cần ràng buộc các tham số cho phương thức.

Câu hỏi

Có cách nào để ràng buộc các tham số để một thể hiện của một Ruby Method như vậy mà khi tôi gọi method.call không có tham số bổ sung, các thông số ràng buộc vẫn truyền cho phương pháp này?

Goal

Đây là một thành ngữ JavaScript phổ biến và tôi nghĩ rằng nó sẽ có ích trong bất kỳ ngôn ngữ. Mục đích là để vượt qua một phương thức M đến một máy thu R trong đó R không cần (hoặc có) tri thức nội tại trong đó (hoặc có bao nhiêu) tham số gửi tới M khi R thực hiện phương thức.

Một JavaScript cuộc biểu tình của cách này có thể có ích

/* this is our receiver "R" */ 
var idiot = function(fn) { 
    console.log("yes, master;", fn()); 
}; 


/* here's a couple method "M" examples */ 
var calculateSomethingDifficult = function(a, b) { 
    return "the sum is " + (a + b); 
}; 

var applyJam = function() { 
    return "adding jam to " + this.name; 
}; 

var Item = function Item(name) { 
    this.name = name; 
}; 


/* here's how we might use it */ 
idiot(calculateSomethingDifficult.bind(null, 1, 1)); 
// => yes master; the sum is 2 

idiot(applyJam.bind(new Item("toast"))); 
// => yes master; adding jam to toast 
+0

Câu hỏi của bạn madam vui lòng? :) –

+1

Tôi hầu như không phải là một tài liệu tham khảo, nhưng tôi chưa bao giờ thấy Ruby được viết theo cách đó. Tôi tò mò ... có lý do cụ thể nào cho cách tiếp cận đó không? Bạn đang cố gắng đạt được điều gì? – Mohamad

+0

@Mohamad đây là thành ngữ JavaScript phổ biến. Tôi đã thêm một số thông tin cho câu hỏi. – naomik

Trả lời

6

Thông thường, phương pháp rebinding không phải là điều bạn làm trong Ruby. Thay vào đó, bạn sử dụng các khối:

# This is our receiver "R" 
def idiot(&block) 
    puts("yes, master; #{block.call}") 
end 


# Here's a couple method "M" examples 
def calculateSomethingDifficult(a, b) 
    return "the sum is #{a + b}" 
end 

def applyJam(object) 
    return "adding jam to " + object.name 
end 

class Item 
    attr_reader :name 
    def initialize(name) 
    @name = name 
    end 
end 


# Here's how we might use it 
idiot do 
    calculateSomethingDifficult(1, 1) 
end 
#=> yes master; the sum is 2 

# You *can* change calling context too (see instance_exec), but I'd 
# discourage it. It's probably better to just pass the object as a 
# parameter. 
idiot do 
    applyJam(Item.new("toast")) 
end 
#=> yes master; adding jam to toast 

Nếu bạn thực sự muốn "ràng buộc" các phương pháp như bạn làm trong JavaScript nó chắc chắn có thể mặc dù:

class Method 
    def bind *args 
    Proc.new do |*more| 
     self.call *(args + more) 
    end 
    end 
end 

Điều đó sẽ làm cho công việc ví dụ của bạn gần như bạn đã mô tả ban đầu:

# make a method 
def sad a, b, c 
    puts a, b, c 
end 

# store method to variable 
b = method(:sad) 

# Get a "bound" version of the method 
b = b.bind(1, 2, 3) 

# call the method without passing additional args 
b.call 

Nếu bạn cần chính xác, bạn có thể xác định Object#bindable_method để trả lại một số lớp học BindableMethod làm những gì bạn muốn. Đối với hầu hết các trường hợp mặc dù tôi nghĩ rằng ở trên sẽ làm việc cho bạn.

+0

Điều này sẽ thực hiện phương pháp tại thời điểm ràng buộc. Vấn đề là để ràng buộc các tham số cho phương thức nhưng trì hoãn việc gọi thực tế của phương thức bị ràng buộc cho đến một thời gian sau đó. – naomik

+0

@naomik Không, nó sẽ không; hãy thử một lần! ;) Có một báo trước mặc dù tôi quên đề cập đến. Một giây trong khi tôi chỉnh sửa câu trả lời của mình. – Ajedi32

+0

Oh bạn nói đúng. Bạn đang gói phương pháp ban đầu với một Proc mới. Tôi hiểu rồi. Hmm ... cho tôi một chút thời gian để suy ngẫm về những tác động ở đây ... – naomik

4

Proc#curry trong Ruby tương tự như bind trong JavaScript.

def happy(a, b, c, d = 100) 
    puts a, b, c, d 
end 

proc = method(:happy).to_proc.curry # proc is now a curried Proc 

b = proc.call(1,2) # b is a curried Proc with 1 and 2 bound as the first arguments 

b.call(3) # Call the proc, providing the 3rd argument 

Bạn không thể trùng lặp mã ví dụ của bạn vì khi proc được gọi với các đối số cần thiết, nó trả về kết quả của proc --- nói cách khác, bạn không thể ràng buộc TẤT CẢ các đối số và sau đó gọi cho proc sau --- bạn phải để lại ít nhất một đối số không bị ràng buộc.

Điều này không nhất thiết phải là một lựa chọn tốt hơn so với mã được cung cấp bởi Ajedi32, nhưng tôi nghĩ rằng nó đáng nói đến vì nó được xây dựng trong Ruby.

Xem tài liệu tại đây: http://ruby-doc.org/core-2.2.0/Proc.html#method-i-curry

+0

Cảm ơn bạn đã chia sẻ – naomik

Các vấn đề liên quan