为什么是Java程序员?因为面向对象的概念一般喜欢用Java来讲,懂面向对象的人一般都懂Java。按照从已知到未知的原则,我给Javascript的面向对象找个方便类比的东东。
1. 猫的构造函数
首字母大写的一个函数,可以通过参数来设置属性(properties)。如下:
function Cat(type) {
this.type = type;
}
一个对象,可以用new来创建:
var whiteCat = new Cat('white');
console.log(whiteCat instanceof Cat); //输出:true
看样子,Cat
很像Java的类。但在Javascript里面,没有类的概念,这只是一个构造函数(Constructor)。对象whiteCat
是构造函数Cat
的一个instance。
console.log(typeof Cat); //输出:function
console.log(typeof whiteCat); //输出:object
2. 小白猫的原型是白猫
Javascript对象,可以有一个原型(prototype)对象。自己没有定义的方法,如果原型对象有定义,也可以直接调用。哈哈,这就像是Java里面的类继承的概念,只不过,Javascript里面没有类,主体是对象。
用如下Object.create
方法可以把一个对象whiteCat
设置成另一个对象littleWhiteCat
的原型:
var littleWhiteCat = Object.create(whiteCat);
whiteCat.say = function() {
console.log("maomao");
}
whiteCat.say(); //输出:maomao
littleWhiteCat.say(); //输出:maomao
可以用如下Object.getPrototypeOf
方法查看一个对象的原型对象:
console.log(Object.getPrototypeOf(littleWhiteCat) == whiteCat); //输出:true
3. 白猫的原型是什么?
前两个概念都比较简单,两个合在一起对于Java程序员来说就有点绕了。
小白猫对象littleWhiteCat
的原型对象是白猫whiteCat
,白猫是用构造函数Cat
创建的,那么白猫的原型对象是什么?
白猫的原型对象不是Cat
,因为Cat
只是个构造函数而已,白猫的原型对象是Cat.prototype
。
console.log(Object.getPrototypeOf(whiteCat) == Cat.prototype); //输出:true
可以把Cat.prototype
看成一个整体,Javascript里面,每个构造函数X
都有一个X.prototype
的对象,作为用new X
创建对象的原型对象。
4. 让猫吃东西
按照前面讲的原型对象的“继承”关系由下向上线条是:
littleWhiteCat ——> whiteCat ——> Cat.prototype
所以,如果想给猫增加个吃东西的方法,只需要对Cat.prototype
下手即可:
Cat.prototype.eat = function() {
console.log(this.type, ': Cat eat fish!');
}
console.log(whiteCat.eat()); //输出:white : Cat eat fish!
console.log(littleWhiteCat.eat()); //输出:white : Cat eat fish!
如果小白猫喜欢吃老鼠,类似Java中方法重载的概念:
littleWhiteCat.eat = function() {
console.log('littleWhiteCat eat mouse!');
}
console.log(whiteCat.eat()); //输出:white : Cat eat fish!
console.log(littleWhiteCat.eat()); //输出:littleWhiteCat eat mouse!
5. 机器猫的构造函数
前面讲的白猫whiteCat
是一个对象,“继承”自Cat.prototype
。如果有一类猫是机器猫,机器猫里有好多只,最有名的是哆啦A梦,哈哈。
创建一个机器猫MachineCat
的构造函数,调用Cat
的构造函数。哆啦A梦dola
就用机器猫的构造函数来创建。
function MachineCat(type) {
this.pocket = 'a lot of good things.';
Cat.call(this, type);
}
var dola = new MachineCat('blue');
以上代码,机器猫MachineCat
和猫Cat
并没有什么关系,哆啦A梦不能称之为猫,也不能调用猫的一些方法,比如eat()
。给他们建立联系,需要如下一个关键操作:
MachineCat.prototype = Object.create(Cat.prototype);
这时,哆啦A梦,不但是机器猫的instance,而且是猫的instance了。这太像Java的类继承了。
var dola = new MachineCat('blue'); // dola需要在机器猫和猫的关系确定后,重新创建
console.log(dola instanceof MachineCat); //输出:true
console.log(dola instanceof Cat); //输出:true
dola.eat(); //输出:blue : Cat eat fish!
这时,“继承”关系由下向上的链条是:
dola ——> MachineCat.prototype ——> Cat.prototype
console.log(Object.getPrototypeOf(dola) == MachineCat.prototype); //输出:true
console.log(Object.getPrototypeOf(MachineCat.prototype) == Cat.prototype); //输出:true
6. 一些奇怪东西的分析
在Javascript里面,一切都是对象。函数本质也是个对象,所以,这个很像Java类的构造函数Cat
,本质也是个对象。那这个对象的原型对象是什么呢?
console.log(Object.getPrototypeOf(Cat) == Function.prototype); //输出:true
类似的,数组,字符串,数字等等,也是对象,也有原型对象:
console.log(Object.getPrototypeOf([1,2,3]) == Array.prototype); //输出:true
console.log(Object.getPrototypeOf(1) == Number.prototype); //输出:true
console.log(Object.getPrototypeOf('abc') == String.prototype); //输出:true
这些奇奇怪怪的xxx.prototype也是对象啊,他们的原型对象一般是:
console.log(Object.getPrototypeOf(Cat.prototype) == Object.prototype); //输出:true
console.log(Object.getPrototypeOf(Function.prototype) == Object.prototype); //输出:true
console.log(Object.getPrototypeOf(Array.prototype) == Object.prototype); //输出:true
console.log(Object.getPrototypeOf(Number.prototype) == Object.prototype); //输出:true
console.log(Object.getPrototypeOf(String.prototype) == Object.prototype); //输出:true
这些貌似Java类的Array等东东,其实都是Javascript里面原生的构造函数:
console.log(typeof Function == 'function'); //输出:true
console.log(typeof Array == 'function'); //输出:true
console.log(typeof Number == 'function'); //输出:true
console.log(typeof String == 'function'); //输出:true
console.log(typeof Object == 'function'); //输出:true
以上,就是Javascript的面向对象概念的素描。没有类的Javascript是不是更好玩呢?