技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> JavaScript --> JavaScript对象继承一瞥

JavaScript对象继承一瞥

浏览:1467次  出处信息

   js创建之初,正值java大行其道,面向对象编程春风正盛,js借鉴了java的对象机制,但仅是看起来像,也就是js的构造函数,如下:

function People(age) {
	this.age = age;
	this.getAge = function (){return this.age};
}

var p1 = new People(20);//People的实例1
var p2 = new People(40);//People的实例2

   上面的代码很像java了,通过new constructor()的方式,可以创建多个实例。

   但上面代码问题是getAge方法会在每个People的实例中存在,如果实例多的话,会浪费很多空间,js采用了牺牲时间,获取空间的方法,js引入了原型理念,将方法放入原型中:

function People(age) {
	this.age = age
}

People.prototype.getAge = function () {return this.age};

   本文就来总结下,如何使用构造函数来实现继承。

场景

   我们假设我们有一个父构造函数People和子构造函数Student,People有一个属性age和一个方法getAge,Student有一个属性num和getNum。

function People(age) {
	this.age = age;
}
People.prototype.getAge = function (){return this.age;};

function Student(num) {
	this.num = num;
}
Student.prototype.getNum = function () {return this.num;};

   我们要实现是Student继承People,这在js里可要费一番力气了。

默认模式

   我们可以利用js的原型机制,将子构造函数的原型属性设置为父构造函数的实例,这是js中比较常用的方式:

function Student(num) {
	this.num = num;
}

Student.prototype = new People();

Student.prototype.getNum = function () {return this.num;};

var stu1 = new Student('123');

   这样做其实基本实现了我们的需求,但如果深入思考上面的方式,其实有几个缺点:

  • 子类无法继承父类的实例属性

  • 会将父类的实例属性,扩展到子类的原型上

  • 修改了子类的原型属性,会导致在stu1上获取constructor属性为People,而不是Student

  •    哦!!!

    借用构造函数

       先来看看如何解决第一个问题,我们可以巧用js的call方法,如果你还不知道这个方法,请移步这里

    function Student(age, num) {
    	People.call(this, age);
    	this.num = num;
    }
    

       我们在子构造函数内部,借用父构造函数,这样就巧妙地在子类中继承了父类的实例化属性。这其实类似java的super关键字。

    共享原型

       再来看看如何解决第二个问题,解决这个问题,其实我们可以将子构造函数的原型更改为父构造函数的原型,而不是父构造函数的实例。

    Student.prototype = People.prototype;
    

       这样就不会将父构造函数的实例属性扩展到子构造函数的原型上了。

       但这样做会导致另一个问题,就是无法再在Student的原型上扩展方法了,因为会扩展同时会扩展到People的原型上。

    临时构造函数

       为了解决上面引发的问题,和第三个问题。我们可以在子构造函数和父构造函数之间,加一层临时构造函数。

    function F() {
    }
    
    F.prototype = People.prototype;
    
    Student.prototype = new F();
    

       这样就可以Student的原型上扩展子构造函数的方法,同时不影响父构造函数的原形了。

       在修复一下constructor属性就ok啦

    Student.prorotype.constructor = Student;
    

    圣杯

       我们将上面的几种方法综合起来,代码看起来就像下面这样子:

    //继承函数
    function inherit(C, P) {
    	var F = function (){};
    	F.prototype = P.prototype;
    	C.prototype = new F();//临时构造函数
    
    	C.prototype.constructor = C;//修复constructor
    	C.uper = P;//存储超类
    }
    
    function People(age) {
    	this.age = age;
    }
    People.prototype.getAge = function (){return this.age;};
    
    function Student(age, num) {
    	Student.uber.call(this, age);
    	this.num = num;
    }
    
    inherit(Student, People);//继承父构造函数
    Student.prototype.getNum = function () {return this.num;};
    

    总结

       本文大部分内容其实出自,《javascript模式》第五章 代码的复用模式。记录下来省的自己每次都要去翻书了,当然主要还是写给MM看的。

建议继续学习:

  1. 在C++里写一个不能被继承的类    (阅读:5769)
  2. PHP面向对象编程的三大特性    (阅读:3452)
  3. 多重继承及虚继承中对象内存的分布    (阅读:3147)
  4. Linux 系统文件描述符继承带来的危害    (阅读:2844)
  5. 关于python和C++中子类继承父类数据的问题    (阅读:2690)
  6. C++ 中的接口继承与实现继承    (阅读:2580)
  7. Javascript继承机制的设计思想    (阅读:2532)
  8. JavaScript 函数、作用域和继承    (阅读:2319)
  9. 再论Javascript的类继承    (阅读:2135)
  10. Javascript继承-原型的陷阱    (阅读:2281)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1