《JavaScript设计模式与开发实践》-面向对象的JavaScript
动态类型语言
编程语言按照数据类型大体分为:静态类型语言和动态类型语言。
静态类型语言在编译时便已确定变量的类型,而动态类型语言的变量类型要到程序运行时,待变量被赋予某个值之后,才会具有某种类型。
在JavaScript中,当我们对一个变量赋值时,显然不需要考虑它的类型,因此JavaScript是一门典型的动态类型语言。
动态类型语言对变量类型的宽容给实际编码带来了很大的灵活性,由于无需进行类型检测,我们可以尝试调用任何对象的任意方法,而无需去考虑它原本是否被设计为拥有该方法。
这一切都建立在鸭子类型的概念上,即如果它走起来像鸭子,叫起来也是鸭子,那么它就是鸭子。
var duck = {
duckSinging: function() {
printf('gagaga');
}
};
var chicken = {
duckSinging: function() {
printf('gagaga');
}
};
var choir = [];
var joinChoir = function(animal) {
if (animal && typeof animal.duckSinging === "function") {
choir.push(animal);
printf("恭喜加入合唱团");
printf("合唱团已有人数" + choir.length);
}
}
joinChoir(duck);
joinChoir(chicken);
由此,实现了动态类型语言中的一个重要原则:面向接口编程,而不是面向实现编程。
多态
多态的实际含义是:同一操作作用域不同的对象上面,可以产生不同的解释和不同的执行结果。
var makeSound = function(animal) {
if (animal instanceof Duck) {
printf('ggaga');
} else if (animal instanceof chicken) {
printf('gegege');
}
}
var Duck = function() {};
var chicken = function() {};
makeSound(new Duck());
makeSound(new chicken());
这段代码确实实现了多态性,但是如何增加一只动物,那么makeSound函数也需要去改动,这显然并不让人满意。
多态背后的思想是将“做什么”和“谁去做及怎样做”分离开来,也就是将“不变的事物”与“可能改变的事物”分离开来。
原型编程范型的一些规则
-
所有的数据都是对象
-
要得到一个对象,不是通过实例化类,而是找到一个对象作为原型并克隆它
-
对象会记住它的原型
-
如果对象无法响应某个请求,它会把这个请求委托给它自己的原型
事实上,JavaScript中的根对象是Object.prototype,它是一个空对象,我们在JavaScript中遇到的每个对象,实际上都是从它克隆而来的。Object.prototype就是它们的原型。
虽然我们经常用new去实例化一个函数,但是在JavaScript中,当使用new运算符来调用函数时,实际上也是先克隆Object.prototype对象,再进行一些其他额外的过程。
我们一直在讨论对象的原型,就JavaScript的真正实现来说,并不能说对象有原型,而应该说对象的构造器有原型。
实际上,虽然JavaScript的对象最初都是又Object.prototype对象克隆而来,但对象构造器的原型并不限于Object.prototype上,而是可以动态指向其他对象。这样一来,当对象a需要借用对象b的能力时,可以有选择性地把对象a的构造器的原型指向对象b,从而达到继承的效果。
var A=function(){};
A.prototype={name:'sven'};
var B=function(){};
B.prototype.new A();
var b=new B();
console.log(b.name);//输出:sven