給object定義method
在Javascript中,可以給對象直接定義方法:
whiteRabbit = {}
whiteRabbit.speak = function(saying) {
console.log(saying);
}
與傳統(tǒng)的面向?qū)ο笳Z言不同的是,這里不需要在類定義中定義一個(gè)對象的方法。這個(gè)說法倒也有例外的地方,比如說在Ruby中可以給某個(gè)對象(而不是類)定義方法:
# 定義Rabbit類
class Rabbit; end
whiteRabbit = Rabbit.new
fatRabbit = Rabbit.new
# 定義對象whiteRabbit的方法speak
def whiteRabbit.speak(saying)
puts saying
end
whiteRabbit.speak(“天生麗質(zhì)嘿!”) # works
fat.speak(“已經(jīng)放棄治療...”) # NoMethodError: undefined method `speak' for #<Rabbit:0x007ff48bcffda0>
但是像在C++和Java這樣的語言中就不行。
apply的作用
首先澄清函數(shù)與方法的區(qū)別,函數(shù)是命令式編程的概念,其不需要綁定在某個(gè)對象上;方法是面向?qū)ο缶幊痰母拍?,需要與一個(gè)對象相綁定。
在函數(shù)式編程中,函數(shù)(代碼片段)是一個(gè)獨(dú)立概念,我們既然可以將其當(dāng)做值傳入傳出,自然也可以將其與任意對象綁定。apply實(shí)現(xiàn)綁定這個(gè)操作,綁定之后,可以利用this指針引用被綁定對象。例子如下:
// 定義speak這個(gè)函數(shù)
function speak(line) {
print("The ", this.adjective, " rabbit says '", line, "'");
}
// 直接將speak函數(shù)設(shè)置為whiteRabbit的speak屬性,然后其就成為方法了
var whiteRabbit = {adjective: "white", speak: speak};
whiteRabbit.speak("Oh my ears and whiskers, how late it's getting!”);
// 動態(tài)綁定speak到fatRabbit上,第一個(gè)參數(shù)是被綁定對象,第二個(gè)參數(shù)是一個(gè)Array,傳speak的參數(shù)
var fatRabbit = {adjective: "fat”};
speak.apply(fatRabbit, [“Yum”]);
fatRabbit.speak("I could sure use a carrot right now.”);
call的作用
和apply類似,只是第二個(gè)參數(shù)不再要求是Array,可以是變參。例如:
speak.call(fatRabbit, “Yum”);
Ruby中的binding
Ruby中的binding基本用不到,它能夠?qū)ontext當(dāng)做變量傳入傳出,例如:
class Demo
def initialize(secret)
@myLittleSecret = secret
end
def get_binding
# binding是個(gè)private方法,要這樣來暴露
binding
end
end
d1 = Demo.new 142857
b1 = d1.get_binding
def unlock(o)
binding = o.get_binding if o.respond_to? :get_binding
eval(“@myLittleSecret”, binding)
end
# 把d1的context傳過來用用
unlock(b1) # => 142857
與Javascript的區(qū)別是沒辦法做動態(tài)的方法與對象綁定。但事實(shí)上,它可以做到源碼級別的代碼片段與環(huán)境上下文,其靈活性是遠(yuǎn)遠(yuǎn)超過前述綁定的。例如我們完全可以把函數(shù)的調(diào)用直接用字符串寫進(jìn)去,有神器eval幫我們做解析執(zhí)行即可。
參考:
[1] M. Haverbeke, Eloquent JavaScript: A Modern Introduction to Programming. No Starch Press, 2011.
[2] http://www.ruby-doc.org/core-2.0.0/Binding.html