设为首页 加入收藏

TOP

JavaScript中类式继承和原型式继承的实现方法和区别(一)
2017-04-26 10:22:53 】 浏览:427
Tags:JavaScript 继承 型式 实现 方法 区别

在所有面向对象的编程中,继承是一个重要的话题。一般说来,在设计类的时候,我们希望能减少重复性的代码,并且尽量弱化对象间的耦合(让一个类继承另一个类可能会导致二者产生强耦合)。关于“解耦”是程序设计中另一个重要的话题,本篇重点来看看在java script如何实现继承。


其它的面向对象程序设计语言都是通过关键字来解决继承的问题(比如extend或inherit等方式)。但是java script中并没有定义这种实现的机制,如果一个类需要继承另一个类,这个继承过程需要程序员自己通过编码来实现。


一、类式继承的实现


1、创建一个类的方式:


//定义类的构造函数
function Person(name) {
    this.name = name || '默认姓名';
}
//定义该类所有实例的公共方法
Person.prototype.getName = function() {
    return this.name;
}


var smith = new Person('Smith');
var jacky = new Person('Jacky');


console.log( smith.getName(), jacky.getName() ); //Smith Jacky



2、继承这个类:这需要分两个步骤来实现,第1步是继承父类构造函数中定义的属性,第2步是继承父类的prototype属性


 


//定义类的构造函数
function Person(name) {
    this.name = name || '默认姓名';
}
//定义该类所有实例的公共方法
Person.prototype.getName = function() {
    return this.name;
}
function Author(name, books) {
    //继承父类构造函数中定义的属性
    //通过改变父类构造函数的执行上下文来继承
    Person.call(this, name);
    this.books = books;
}


//继承父类对应的方法
Author.prototype = new Person(); //Author.prototype.constructor === Person
Author.prototype.constructor = Author; //修正修改原型链时造成的constructor丢失
Author.prototype.getBooks = function() {
    return this.books;
};


//测试
var smith = new Person('Smith');
var jacky = new Author('Jacky', ['BookA', 'BookB']);


console.log(smith.getName()); //Smith
console.log(jacky.getName()); //Jacky
console.log(jacky.getBooks().join(', ')); //BookA, BookB
console.log(smith.getBooks().join(', ')); //Uncaught TypeError: smith.getBooks is not a function


 


从测试的结果中可以看出,Author正确继承了Person,而且修改Author的原型时,并不会对Person产生影响。这其中的关键一句就是 Author.prototype = new Person(),要与Author.prototype = Person.prototype区分开来。前者产生了一个实例,这个实例有Person.prototype的副本(这里先这么理解,后面有更详细的解析)。后者是指将两者的prototype指向同一个原型对象。


那么,这也意味着每次继承都将产生一个父类的副本,肯定对内存产生消耗,但为了类式继承这个内存开销必须得支付,但还可以做得更节省一点:Author.prototype = new Person()这一句其实多执行了构造函数一次(而这一次其实只需在子类构造函数中执行即可),尤其是在父类的构造函数很庞大时很耗时和内存。修改一下继承的方式,如下:


Author.prototype = (function() {
    function F() {}
    F.prototype = Person.prototype;
    return new F();
})();


如上所示的代码,new时,去掉了对父类的构造函数的调用,节省了一次调用的开销。


3、类式继承显著的特点是每一次实例化对象时,子类都将执行一次父类的构造函数。如果E继承了D,D继承了C,C继承了B,B继承了A,在实例化一个E时,一共要经过几次构造函数的调用呢?


 


/*继承方法的函数*/
function extend(son, father) {
    function F() {}
    F.prototype = father.prototype;
    son.prototype = new F();
    son.prototype.constructor = son;
}
//A类
function A() {
    console.log('A()');
}
A.prototype.hello = function() {
    console.log('Hello, world.');
}
//B类
function B() {
    A.call(this);
    console.log('B()');
}
extend(B, A);
//C类
function C() {
    B.call(this);
    console.log('C()');
}
extend(C, B);
//D类
function D() {
    C.call(this);
    console.log('D()');
}
extend(D, C);
//E类
function E() {
    D.call(this);
    console.log('E()');
}
extend(E, D);


//创建一个E的实例
var e = new E(); //A() B() C() D() E()
e.hello(); //hello, world.


 


5次,这还只是实例化一个E时调用的次数。所以,我们应该尽可能的减少继承的级别。但这并不是说不要使用这种类式继承,而是应该根据自己的应用场合决定采用什么方法。


二、原型式继承


1、先来看一段代码:我们先将之前类式继承中的继承prototype那一段改成另一个函数clone,然后通过字面量创建一个Person,最后让Author变成Person的克隆体。


 


//这个函数可以理解为克隆一个对象
function clone(object) {
    function F() {}
  &nb

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Java基础--接口与反射总结 下一篇TCP timestamp 相关知识

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目