转载自廖雪峰的javascript教程
原型继承
在传统的基于Class的语言如Java、C++中,继承的本质是扩展一个已有的Class,并生成新的Subclass。
由于这类语言严格区分类和实例,继承实际上是类型的扩展。但是,JavaScript由于采用原型继承,我们无法直接扩展一个Class,因为根本不存在Class这种类型。
但是基于js的原型特性,我们也可以实现继承。
1 function Student(props) { 2 this.name = props.name||'unNamed'; 3 } 4 5 Student.prototype.hello = function () { 6 alert('Hello, ' + this.name + '!'); 7 }
我们先创建一个基于student扩展出来的primaryStudent,
1 function PrimaryStudent(props) { 2 // 调用Student构造函数,绑定this变量: 3 Student.call(this, props); 4 this.grade = props.grade || 1; 5 }
现在,primaryStudent的原型链是:
primarystudent-->PrimaryStudent.prototype-->object.prototype-->null
而我们要实现继承,即想要的得到的原型链是:
primarystudent-->PrimaryStudent.prototype-->Student.prototype-->object.prototype-->null
我们第一想到的是:
1 PrimaryStudent.prototype = Student.prototype;
但是这样不行,因为这样他两的原型是一样的,就不叫继承。
我们需要借助一个中间对象来实现正确的原型链,并且这个中间对象的原型要指向Student.prototype ,实现方法如下:
1 // PrimaryStudent构造函数: 2 function PrimaryStudent(props) { 3 Student.call(this, props); 4 this.grade = props.grade || 1; 5 } 6 7 // 空函数F: 8 function F() { 9 } 10 11 // 把F的原型指向Student.prototype: 12 F.prototype = Student.prototype; 13 14 // 把PrimaryStudent的原型指向一个新的F对象,F对象的原型正好指向Student.prototype: 15 PrimaryStudent.prototype = new F(); 16 17 // 把PrimaryStudent原型的构造函数修复为PrimaryStudent: 18 PrimaryStudent.prototype.constructor = PrimaryStudent; 19 20 // 继续在PrimaryStudent原型(就是new F()对象)上定义方法: 21 PrimaryStudent.prototype.getGrade = function () { 22 return this.grade; 23 }; 24 25 // 创建xiaoming: 26 var xiaoming = new PrimaryStudent({ 27 name: '小明', 28 grade: 2 29 }); 30 xiaoming.name; // '小明' 31 xiaoming.grade; // 2 32 33 // 验证原型: 34 xiaoming.__proto__ === PrimaryStudent.prototype; // true 35 xiaoming.__proto__.__proto__ === Student.prototype; // true 36 37 // 验证继承关系: 38 xiaoming instanceof PrimaryStudent; // true 39 xiaoming instanceof Student; // true
将继承这个动作进行封装以简化代码和复用
1 function inherits(Child, Parent) { 2 var F = function () {}; 3 F.prototype = Parent.prototype; 4 Child.prototype = new F(); 5 Child.prototype.constructor = Child; 6 } 7 8 function Student(props) { 9 this.name = props.name || 'Unnamed'; 10 } 11 12 Student.prototype.hello = function () { 13 alert('Hello, ' + this.name + '!'); 14 } 15 16 function PrimaryStudent(props) { 17 Student.call(this, props); 18 this.grade = props.grade || 1; 19 } 20 21 // 实现原型继承链: 22 inherits(PrimaryStudent, Student); 23 24 // 绑定其他方法到PrimaryStudent原型: 25 PrimaryStudent.prototype.getGrade = function () { 26 return this.grade; 27 };