2013-08-28 168 views
9

JavaScript的快樂時光樂趣土地JavaScript的Function.prototype.bind是否有Ruby等價物?

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

輸出。好極了!

1 2 3 

在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 

所需的輸出

1, 2, 3 

對於它的價值,我知道JavaScript可以改變的第一個參數的結合上下文傳遞給.bind。在Ruby中,即使我無法更改上下文,我也會很開心。我主要需要簡單地將參數綁定到方法。

問題

是否有參數綁定到一個Ruby Method的實例,例如,當我打電話method.call沒有額外的參數,被綁定參數是仍然傳遞給方法的方法嗎?

目標

這是一個常見的JavaScript的成語,我認爲這將是任何語言有用。目標是將方法M傳遞給接收方R,其中R不需要(或具有)當R執行該方法時要將哪些(或多少)參數發送給M的固有知識。這如何可能是有用的

/* 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

您的問題請問? :) –

+1

我不是一個參考,但我從來沒有見過Ruby寫的那種方式。我很好奇......這種方法有一個特別的原因嗎?你想達到什麼目的? – Mohamad

+0

@Mohamad這是一個常見的JavaScript習慣用法。我爲這個問題添加了一些信息。 – naomik

回答

6

通常

一個JavaScript示範,重新綁定方法是不是你在Ruby中做一些事情。相反,您可以使用塊:

# 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 

如果你真的想「綁定」的方法,如你在JavaScript這樣做是絕對有可能,但:

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

這應該使你的榜樣工作幾乎正如你最初描述的那樣:

# 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 

如果你需要它確切的,你可以定義Object#bindable_method返回一些你想要的BindableMethod類。儘管我認爲大多數情況下上述都適合你。

+0

這將在綁定時執行該方法。重點是將參數綁定到方法,但推遲綁定方法的實際調用,直到以後的時間。 – naomik

+0

@naomik不,它不會;試一試! ;)有一個警告,但我忘了提及。一秒鐘,我編輯我的答案。 – Ajedi32

+0

哦,你是對的。您正在用新的Proc包裝原始方法。我現在明白了。嗯...給我一點時間來思考這裏的含義... – naomik

4

Proc#curry Ruby中類似於JavaScript中的bind

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 

不能完全複製你的示例代碼,因爲當咖喱PROC被稱爲所需的參數,它返回PROC的結果---換句話說,你不能約束所有的參數和然後再調用proc ---你必須至少保留一個參數。

這不一定比Ajedi32提供的代碼一個更好的選擇,但我認爲這是值得一提,因爲它的內置到Ruby。

看到文檔在這裏:http://ruby-doc.org/core-2.2.0/Proc.html#method-i-curry

+0

感謝您的分享 – naomik

相關問題