Module#constants
能够获取当前范围内全部的常量c#
Module.constants
获取当前程序中全部顶层的常量安全
Module.nesting
能够获得当前代码所在的路径ruby
ClassName.ancestors
能够获取类的祖先链闭包
require
和 load
的区别:ui
load
用于加载代码,require
用于导入类库代理
require
对每一个文件只加载一次,而 load
每次调用时都会再次运行所加载的文件code
load
有反作用,常量(包括类)有可能污染当前程序的命名空间,load('xxx.rb', true)
才约等于 require 'xxx.rb'
对象
方法查找口诀:向右一步,再向上继承
include
和 prepend
的异同:作用域
共同点是,都将模块加入包含者的祖先链
不一样点是,include
引入的模块在包含者的上面,prepend
引入的模块在包含者的下面
每一个模块都只会引入一次,若是该模块已经存在于祖先链,则再次引入不会有任何影响
私有规则:
若是调用方法的接收者不是本身,那就必须明确指明接收者
私有方法只能经过隐性的接收者调用
顶层上下文的 self
是 main
对象
在类和模块的定义中,在任何方法定义之外,self
就是类或模块自己
refine
和打开类的异同:
二者均可以打开类定义,给类添加新的方法
打开类全局有效,而 refine
只在 using
之后并在 using
做用域之内才有效
小结:
对象由一组实例变量和类的引用组成
对象的方法存在于对象所属的类中
类自己是 Class
类的对象
Class
类是 Module
的子类,类只是比模块多了 new
和 superclass
方法
类祖先链的最顶端是 BasicObject
实例变量永远被认为是 self
的实例变量
动态派发:person.hello('Ruchee')
与 person.send(:hello, 'Ruchee')
等价
能够用 send
调用任何方法,包括私有方法
能够用 public_send
限制对私有方法的调用
动态方法:使用 define_method
来定义方法
幽灵方法:使用 method_missing
截取全部未定义的方法调用
动态代理:用幽灵方法捕获方法调用,并转发给另一个对象
每次覆写 method_missing
方法时,最好也同时覆写 respond_to_missing?
方法,以使得能够用 respond_to_missing?
来正确检测是否是存在某幽灵方法
对于方法,找不到时会被 method_missing
截取,而对于常量,找不到时一样会被一个叫 const_missing
的方法截取
白板类:拥有极少方法的类,能够避免祖先链中存在同名方法而致使 method_missing
调用不到的问题
Module#undef_method
和 Module#remove_method
的异同:
相同点都是删除方法
undef_method
删除全部的方法,包括继承来的
remove_method
只删除本身的方法,继承来的方法保留
能够用 block_given?
检测方法调用是否有传递代码块,代码块也就是闭包
全局变量能够在任何做用域中访问和修改
三个做用域门:class
、module
、def
穿越做用域门:
用 Class.new
穿越 class
做用域
用 Module.new
穿越 module
做用域
用 define_method
穿越 def
做用域
上下文探针:
instance_val
在一个对象的上下文中执行代码块
instance_exec
和 instance_val
功能基本一致,但容许给代码块传入参数
延迟执行:将代码块转成 proc
存储,后续再用 Proc#call
调用执行
建立 proc
的几种方法,如下各代码段做用等价
inc = Proc.new { |x| x + 1 } puts inc.call(10) inc = lambda { |x| x + 1 } puts inc.call(10) inc = ->x { x + 1 } puts inc.call(10) def create_proc (&block) block end inc = create_proc { |x| x + 1 } puts inc.call(10) def test (&inc) inc.call(10) end puts test { |x| x + 1 } def test yield 10 end puts test { |x| x + 1 } class Test def inc (x) x + 1 end end inc = Test.new.method :inc puts inc.call(10)
定义方法时,最后一个参数以 &
打头能够将传递给该方法的代码块转成 proc
;而调用方法时,在保存 proc
的变量名前加 &
能够将 proc
转回代码块
Proc
与 Lambda
的区别:
用 lambda
方法建立的 Proc
称为 lambda
,而用其余方式建立的则称为 proc
(能够用 Proc#lambda?
检测是否是 lambda
)
lambda
里面的 return
仅从该 lambda
中返回,而 proc
里面的 return
倒是从定义该 proc
的做用域中返回
在参数适应能力上,proc
适应能力更强,而 lambda
对传递的参数个数要求严格
综合 return
和参数,lambda
的表现更像真实的方法:严格检查参数个数,只从本身的代码区域返回
Proc
和 Lambda
return
的差别代码示例:
def test l = -> { return 10 } l.call * 2 end puts test # 输出 20 def test p = Proc.new { return 10 } p.call * 2 # 这一行代码压根执行不到,前一行就已经返回了 end puts test # 输出 10
能够用 Method#unbind
或 Module#instance_method
将一个方法变成自由方法,也能够用 UnboundMethod#bind
或 Module#define_method
再次将自由方法绑定到某个对象
Module#class_eval
能够在不使用 class
关键字的状况下修改当前类
Module#module_eval
是 Module#class_eval
的别名
class_eval
和 module_eval
一样有孪生方法 class_exec
和 module_exec
类变量和类实例变量的区别:
类变量以 @@
打头,而类实例变量以 @
打头
类变量能够被子类或类的实例所使用
类变量的值能够在类定义之外的区域被修改,尽管会获得一个警告
单件方法:在单个对象上定义,且只对单个对象生效的方法
可使用 def obj.xxx
定义单件方法,也可使用 Object#define_singleton_method
方法来定义,能够用 Object.singleton_methods
获取某个对象所有的单件方法
类方法的实质:类方法其实就是一个类的单件方法
单件类:
保存一个对象全部的单件方法
只有一个实例,不能被继承
在类继承链中不可见,只能用 Object#singleton_class
或 class<<
来获取
若是将单件类从继承链标识出来,它是在该对象所属类下方的,也就是对象的方法调用是先查找的单件类,再查找的类自己
单件类的超类是该单件类所归属类的超类的单件类,正由于如此,子类才能够调用到父类的类方法,由于类方法就是类的单件方法,保存在单件类之中,而方法调用会先查找单件类
定义类方法的三种方式:
def Hello.hello # xxx end class Hello def self.hello # xxx end end class Hello class <<self def hello # xxx end end end
include
和 extend
include
是在类层面包含模块,所包含模块的方法将成为类的实例方法
extend
是在单件类层面包含模块,所包含模块的方法将成为单件类的实例方法,也就是类的类方法
extend
实例:
module HelloModule def hello "Hello, World" end end class HelloClass # 写法1 class <<self include HelloModule end # 写法2 extend HelloModule end puts HelloClass.hello
编写环绕别名的三个步骤:
给方法定义一个别名
重定义这个方法
在新方法中调用老方法
Binding
:一个用对象表示的完整做用域,能够用 Kernel#binding
方法捕获当前做用域,而后能够经过 eval
方法在这个绑定对象所携带的做用域中执行代码
TOPLEVEL_BINDING
:表示顶级做用域的绑定对象,能够在程序的任何地方访问到
全局变量 $SAFE
用于控制安全级别,默认为 0
,可设置值为 0
到 3
Object#instance_variable_set
和 Object#instance_variable_get
可用来操做实例变量