前言
nodejs中完全没有class的这个概念,这点跟PHP,JAVA等面向对象的语言很不一样,没有class跟object的区分,那么nodejs是怎么样实现继承的呢?
对象
对象是由属性跟方法组成的一个东西,就像下面这样:
var animal = {
name: "animal",
eat: function () {
console.log('%s is eating', this.name);
}
};
animal.eat(); //animal is eating.
由于nodejs中object完全不和class关联,我们可以自由的给对象添加属性和方法:
animal.color = 'black';
animal.say = function () {
console.log('I am color %s', this.color);
}
console.log(animal.color); //black
animal.say(); //I am color black
怎么像面向对象里的类那样实现继承?
继承是面向对象中的重要概念,实际上是把两个对象建立关联;nodejs中每个对象都有一个__proto__属性,要建立两个对象之间的关联就要用到这个属性了:一个对象可以使用__proto__关联另外一个对象(这个对象就是原型):
var cat = {
name: 'cat',
__proto__: animal
};
var dog = {
name: 'dog',
__proto__: animal
};
cat.eat(); //cat is eating
dog.eat(); //dog is eating
对象cat的原型是animal,对象dog的原型也是animal,并且它们两个都没有定义eat()方法,那是怎么调用eat()方法的呢?
答案是nodejs的机制,当cat对象调用eat方法时,cat对象会现在自己的方法中寻找eat方法,如果找不到,就会去原型的方法中寻找,如果原型中找不到,就会去原型的原型中去寻找...最后就会去Object那里去找,如果还找不到,那就是这个方法未定义了。
这样,animal、cat、dog这三个对象通过__proto__建立起了一个原型链。在这里,dog跟cat对象的name属性覆盖了animal的name属性,还有this,在cat跟dog对象在调用eat方法时,分别指向了cat跟dog对象。
让nodejs可以new出对象来,更贴近面向对象编程
为了让nodejs内的对象可以像面向对象编程那样可以new出一个对象实例,nodejs提供了一个叫做构造函数的东西:
function Student(name) {
this.name = name;
this.sayHello = function () {
console.log('Hello, my name is %s', this.name);
}
}
var tom = new Student('Tom');
var mike = new Student('Mike');
tom.sayHello(); //Hello, my name is Tom
mike.sayHello(); //Hello, my name is Mike
为了让代码更规范,构造函数的名称首字母要大写。在这里有没有发现一个问题,传统的面向对象编程中,方法都是定义在类中的,我们这里的代码是定义在对象上的,这样就意味着每一个由构造函数new出来的对象都附带一个sayHello的方法,这样太浪费空间了。于是,nodejs就创造出了一种更高效的方法,将sayHello方法放到别的地方去。
还记得刚才说的原型链吗?当一个对象调用方法时,会顺着原型链向上找,所以我们可以创建一个原型对象,将要调用的方法放到这个原型对象中,让tom、mike这些从Student创建的对象指向这个原型就行了:
function Student(name) {
this.name = name;
}
Student.prototype = {
sayHello: function () {
console.log('Hello, my name is %s', this.name);
}
}
var tom = new Student('Tom');
var mike = new Student('Mike');
tom.sayHello(); //Hello, my name is Tom
mike.sayHello(); //Hello, my name is Mike
每当new Student()时,确实会创建一个新的对象,并且把这个对象的原型__proto__指向Student.prototype这个对象,这样一来就能找到sayHello()方法了,从而能减少内存消耗的实现了面向对象编程的继承了。