Pregunta

In javascript closure, 'this' reference to the object which actually make the function call.

Do ruby Proc/lambda have 'this' function too?

If not, what should I do to if I want 'this' in ruby? except passing the current object to Proc/lambda by parameters.

¿Fue útil?

Solución

this is not part of the concept of a function or closure in general. A function is simply a thing you can call with arguments; what does "current object" has to do with it? this existing in all functions in JavaScript comes from the peculiar way that methods work in that language.

In JavaScript, all functions have a concept of this because in JavaScript, there is no separation between methods and functions. Any function could potentially be used as a method; you can add a method to an object simply by assigning a function as an attribute of the object. Furthermore, in JavaScript, a function does not have an explicit parameter for the current object (unlike e.g. Python); so how does a method have access to its object? When you run a method call expression, it will pass the object that you called it on as an implicit this parameter to the function. However, if you get the function out using the attribute and call it manually just like any other function, this will be the global object (or in strict mode, undefined).

In other words, in JavaScript when you get a method out of an object by attribute, it is an "unbound method" -- it does not know the object it came from; and conversely when you put a function into an object as a method by attribute, that function did not need to know the object to start with -- the object will be passed to it magically by the method call syntax at the time it is called. You can also artificially supply the this argument to a function by using the .call() or .apply() methods on the function (obj.foo(x) is equivalent to obj.foo.call(obj, x)).

In Ruby, there is complete separation between methods and anonymous functions. Anonymous functions, created using lambda, proc, or Proc.new, etc. are data, and can be stored in variables. They are called with different syntax (call or []) than methods. Methods are defined using def, and you can't get it as data by simply writing its name (that will call it). It is possible to get a method out of an object using the method method on an object, giving the method name, and it returns a Method object. You can use a Method object like a Proc object, e.g. you can call call on it; you can even convert it to a Proc with to_proc. Unlike JavaScript, there is a distinction between bound methods (class Method) an unbound methods (class UnboundMethod). When you get a method out of an object, it is bound -- it knows its object; you can unbind it and bind it to another object if you want.

Also, in Ruby, you can't just take a Proc and just attach it to an object and make it a method, because methods have syntax (e.g. @some_var) that are not valid in Proc. To add a method to an object, you would use instance_exec and put the method definition (def) in the block.

So in short, the concept of this in closures deals with a unique situation in JavaScript not found in most languages. And in particular, the issue does not come up in Ruby because Ruby's objects' methods are bound methods, and also one cannot arbitrarily insert closures as methods.

P.S. others have commented on capturing the self from where a closure is defined into the closure. However, that's not what this in JavaScript is about at all.

Otros consejos

You can use self if you initialize the lambda or proc within a Ruby object. For example:

class Example

  def name
    "Example"
  end

  def test
    lambda{ puts self.name}.call
  end

end

example = Example.new
example.test # "Example"

For a more detailed explanation of Ruby's self see: http://sidtalk.wordpress.com/2008/10/06/what-exactly-is-ruby-self/.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top