给object定义method
在Javascript中,可以给对象直接定义方法:
whiteRabbit = {}
whiteRabbit.speak = function(saying) {
console.log(saying);
}
与传统的面向对象语言不同的是,这里不需要在类定义中定义一个对象的方法。这个说法倒也有例外的地方,比如说在Ruby中可以给某个对象(而不是类)定义方法:
# 定义Rabbit类
class Rabbit; end
whiteRabbit = Rabbit.new
fatRabbit = Rabbit.new
# 定义对象whiteRabbit的方法speak
def whiteRabbit.speak(saying)
puts saying
end
whiteRabbit.speak(“天生丽质嘿!”) # works
fat.speak(“已经放弃治疗...”) # NoMethodError: undefined method `speak' for #<Rabbit:0x007ff48bcffda0>
但是像在C++和Java这样的语言中就不行。
apply的作用
首先澄清函数与方法的区别,函数是命令式编程的概念,其不需要绑定在某个对象上;方法是面向对象编程的概念,需要与一个对象相绑定。
在函数式编程中,函数(代码片段)是一个独立概念,我们既然可以将其当做值传入传出,自然也可以将其与任意对象绑定。apply实现绑定这个操作,绑定之后,可以利用this指针引用被绑定对象。例子如下:
// 定义speak这个函数
function speak(line) {
print("The ", this.adjective, " rabbit says '", line, "'");
}
// 直接将speak函数设置为whiteRabbit的speak属性,然后其就成为方法了
var whiteRabbit = {adjective: "white", speak: speak};
whiteRabbit.speak("Oh my ears and whiskers, how late it's getting!”);
// 动态绑定speak到fatRabbit上,第一个参数是被绑定对象,第二个参数是一个Array,传speak的参数
var fatRabbit = {adjective: "fat”};
speak.apply(fatRabbit, [“Yum”]);
fatRabbit.speak("I could sure use a carrot right now.”);
call的作用
和apply类似,只是第二个参数不再要求是Array,可以是变参。例如:
speak.call(fatRabbit, “Yum”);
Ruby中的binding
Ruby中的binding基本用不到,它能够将context当做变量传入传出,例如:
class Demo
def initialize(secret)
@myLittleSecret = secret
end
def get_binding
# binding是个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的区别是没办法做动态的方法与对象绑定。但事实上,它可以做到源码级别的代码片段与环境上下文,其灵活性是远远超过前述绑定的。例如我们完全可以把函数的调用直接用字符串写进去,有神器eval帮我们做解析执行即可。
参考:
[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