Ruby方法查找(与JavaScript比较)

Ruby方法查找(与JavaScript比较),javascript,ruby,inheritance,prototypal-inheritance,Javascript,Ruby,Inheritance,Prototypal Inheritance,我想更好地理解Ruby中的对象如何在类和模块中定义访问方法。具体来说,我想将其与JavaScript(我更熟悉JavaScript)进行比较和对比 在JavaScript中,对象在对象本身上查找方法,如果在那里找不到,它将在原型对象上查找方法。此过程将继续,直到到达Object.prototype // JavaScript Example var parent = { someMethod: function () { console.log( 'Inside Parent' );

我想更好地理解Ruby中的对象如何在类和模块中定义访问方法。具体来说,我想将其与JavaScript(我更熟悉JavaScript)进行比较和对比

在JavaScript中,对象在对象本身上查找方法,如果在那里找不到,它将在原型对象上查找方法。此过程将继续,直到到达
Object.prototype

// JavaScript Example
var parent = {
  someMethod: function () {
    console.log( 'Inside Parent' );
  }
};

var child = Object.create( parent );
child.someMethod = function () {
  console.log( 'Inside Child' );
};

var obj1 = Object.create( child );
var obj2 = Object.create( child );

obj1.someMethod(); // 'Inside Child'
obj2.someMethod(); // 'Inside Child'
在JavaScript示例中,
obj1
obj2
都没有对象本身的
someMethod
函数。需要注意的关键是:

  • child
    对象中有一个
    someMethod
    函数的副本,并且
    obj1
    obj2
    都委托给
    child
    对象
  • 这意味着
    obj
    obj2
    在对象本身上都没有
    someMethod
    函数的副本
  • 如果
    子对象
    没有定义
    someMethod
    函数,则委托将继续到
    父对象
  • 现在我想将其与Ruby中的类似示例进行对比:

    # Ruby Example
    class Parent
      def some_method
        put 'Inside Parent'
      end
    end
    
    class Child < Parent
      def some_method
        puts 'Inside Child'
      end
    end
    
    obj1 = Child.new
    obj2 = Child.new
    
    obj1.some_method  # 'Inside Child'
    obj2.some_method  # 'Inside Child'
    
    #Ruby示例
    班级家长
    定义某些方法
    把“放在父母里面”
    结束
    结束
    类子<父
    定义某些方法
    把“孩子里面”
    结束
    结束
    obj1=Child.new
    obj2=Child.new
    obj1.some_方法#“内部子对象”
    obj2.some_方法#“内部子对象”
    
    以下是我的问题:

  • Ruby代码中的
    obj1
    obj2
    是否各自拥有
    some\u方法的副本?或者它与JavaScript类似,在JavaScript中,两个对象都可以通过另一个对象(在本例中,通过子类)访问
    some_方法
  • 类似地,当在Ruby中考虑继承时,每个Ruby对象是否都有一个相同名称的所有类和超类方法的副本

  • 我的直觉告诉我,Ruby对象没有从类继承的、混合在模块和超类中的方法的单独副本。相反,我的直觉是Ruby处理方法查找的方式与JavaScript类似,在JavaScript中,对象检查对象本身是否有方法,如果没有,则在对象的类中查找方法,混合在模块中,和超类,直到查找到达
    BasicObject

    让我们在IRB会话中继续使用您的示例,看看我们可以学到什么:

    > obj1.method(:some_method)
    => #<Method: Child#some_method>
    > obj1.method(:some_method).source_location
    => ["(irb)", 8]
    > obj2.method(:some_method)
    => #<Method: Child#some_method>
    > obj2.method(:some_method).source_location
    => ["(irb)", 8]
    
    >obj1.method(:some_方法)
    => #
    >obj1.方法(:某些方法)。源位置
    =>[“(内部评级)”,8]
    >obj2.方法(:某些方法)
    => #
    >obj2.method(:某些方法)。源位置
    =>[“(内部评级)”,8]
    
    好的,那么同一类的两个对象有相同的方法。我想知道这是否总是真的

    > obj1.instance_eval do
    >   def some_method
    >     puts 'what is going on here?'
    >   end
    > end
    => nil
    > obj1.some_method
    what is going on here?
    => nil
    > obj2.some_method
    Inside Child
    => nil
    > obj1.method(:some_method)
    => #<Method: #<Child:0x2b9c128>.some_method>
    > obj1.method(:some_method).source_location
    => ["(irb)", 19]
    
    >obj1.instance\u eval do
    >定义某些方法
    >“这里发生了什么事?”
    >结束
    >结束
    =>零
    >obj1.u方法
    这是怎么回事?
    =>零
    >obj2.u方法
    内童
    =>零
    >obj1.方法(:某些方法)
    => #
    >obj1.方法(:某些方法)。源位置
    =>[“(内部评级)”,19]
    
    那很有趣

    詹姆斯·科格兰(James Coglan)有一篇很好的博客文章,对其中的许多问题都给出了比我现在更好的解释

    当考虑这一点的时候,也可能是有趣的。想想这个系统有多少是解释器的一个实现细节,在MRI、JRuby和Rubinius中可以进行不同的处理,以及Ruby程序要在所有这些系统中一致地执行到底需要什么一致性。

    更多值得思考的东西

    > obj1.instance_eval do
    >  def some_method
    >    puts "Inside Instance"
    >    super
    >  end
    > end 
    => :some_method
    Inside Instance
    Inside Child
    
  • Ruby代码中的
    obj1
    obj2
    是否各自拥有
    some\u方法的副本?或者它与JavaScript类似,在JavaScript中,两个对象都可以通过另一个对象(在本例中,通过子类)访问
    some_方法
  • 你不知道。Ruby语言规范只是说“如果您这样做,就会发生这种情况”。然而,它并没有规定实现这一目标的具体方式。每个Ruby实现都可以按照自己认为合适的方式自由实现,只要结果与规范的结果相匹配,规范就不在乎这些结果是如何获得的

    你不知道。如果实现保持适当的抽象,您就不可能知道它们是如何实现的。这就是抽象的本质。(事实上,这几乎就是抽象的定义。)

  • 类似地,当在Ruby中考虑继承时,每个Ruby对象是否都有一个相同名称的所有类和超类方法的副本
  • 同上

    目前有很多Ruby实现,过去甚至有更多的Ruby实现,处于不同的完成阶段。其中一些实现(ed)了自己的对象模型(例如MRI、YARV、Rubinius、MRuby、Topaz、tinyrb、Rubygollightly),一些位于现有对象模型之上,他们试图将其融入其中(例如Java上的XRuby和JRuby、CLI上的Ruby.NET和IronRuby、SmallRuby上的smalltalk.rb、Alumina和MagLev、Objective-C/Cocoa上的MacRuby和RubyMoon、Parrot上的Cardinal、ActionScript/Flash上的Red Sun、SAP/ABAP上的BlueRuby、ECMAScript上的HotRuby和Opal.rb)

    谁能说所有这些实现的工作原理完全相同

    我的直觉告诉我,Ruby对象没有从类继承的、混合在模块和超类中的方法的单独副本。相反,我的直觉是Ruby处理方法查找的方式类似于JavaScript,在JavaScript中,对象检查对象本身是否有方法,如果没有,则在对象的类中查找方法,混合在模块和超类中,直到查找达到
    BasicObject

    尽管我在上面写了些什么,但这是一个合理的假设,事实上,它是如何实现的
    ruby -e 'p ObjectSpace.each_object(String).count'
    # => 10013
    
    struct Object
      object_id: Id
      ivars: Dictionary<Symbol, *Object>
      class: *Class
    end
    
    struct Module
      methods: Dictionary<Symbol, *Method>
      constants: Dictionary<Symbol, *Object>
      cvars: Dictionary<Symbol, *Object>
    end
    
    struct Class
      methods: Dictionary<Symbol, *Method>
      constants: Dictionary<Symbol, *Object>
      cvars: Dictionary<Symbol, *Object>
      superclass: *Class
    end
    
    struct Object
      object_id: Id
      ivars: Dictionary<Symbol, *Object>
      class: *Class
      singleton_class: Class
    end
    
    struct Module
      methods: Dictionary<Symbol, *Method>
      constants: Dictionary<Symbol, *Object>
      cvars: Dictionary<Symbol, *Object>
      mixins: List<*Module>
    end
    
    struct Class
      methods: Dictionary<Symbol, *Method>
      constants: Dictionary<Symbol, *Object>
      cvars: Dictionary<Symbol, *Object>
      superclass: *Class
      mixins: List<*Module>
    end
    
    struct Object
      object_id: Id
      ivars: Dictionary<Symbol, *Object>
      class: *Class
      singleton_class: Class
    end
    
    struct Class
      methods: *Dictionary<Symbol, *Method>
      constants: *Dictionary<Symbol, *Object>
      cvars: *Dictionary<Symbol, *Object>
      superclass: *Class
      visible?: Bool
    end
    
    M′ = Class.new(
      methods = M->methods
      constants = M->constants
      cvars = M->cvars
      superclass = C->superclass
      visible? = false
    )
    
    C->superclass = *M'
    
    def lookup(meth, obj)
      c = obj->class
    
      until res = c->methods[meth]
        c = c->superclass
        raise MethodNotFound, meth if c.nil?
      end
    
      res
    end