2013-08-28 225 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

相关问题