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
可用來操做實例變量