黑马程序员技术交流社区

标题: 【上海校区】类的继承 [打印本页]

作者: 不二晨    时间: 2018-7-31 09:36
标题: 【上海校区】类的继承
一、何为继承
继承,是子类继承父类的特征和行为,使得子类对象具有父类的实例域和方法。继承是面向对象编程中,不可或缺的一部分。
1.1 优点1.2 缺点二、例子例子以图书馆中的书入库归类为例。以下是简化后的父类Book(也可称为基类)。目的是通过继承该父类,产出Computer(计算机)子类。并且,子类拥有新方法say,输出自己的书名。
function Book(){    this.name = ''; // 书名    this.page = 0; // 页数    this.classify = ''; // 类型}Book.prototype = {    constructor: Book,    init: function(option){        this.name = option.name || '';        this.page = option.page || 0;        this.classify = option.classify || '';    },    getName: function(){        console.log(this.name);    },    getPage: function(){        console.log(this.page);    },    getClassify: function(){        console.log(this.classify);    }};复制代码接下来会讲解子类Computer几种继承方式的实现和优化方法。开始飙车~
三、实例式继承function Computer(){    Book.apply(this, arguments);}Computer.prototype = new Book();Computer.prototype.constructor = Computer;Computer.prototype.init = function(option){    option.classify = 'computer';    Book.prototype.init.call(this, option);};Computer.prototype.say = function(){    console.log('I\'m '+ this.name);}复制代码3.1 调用父类构造器进行初始化function Computer(){    Book.apply(this, arguments);}复制代码Computer的构造函数里,调用父类的构造函数进行初始化操作。使子类拥有父类一样的初始化属性。
3.2 将父类的原型传递给子类Computer.prototype = new Book();使用new操作符对父类Book进行实例化,并将实例对象赋值给子类的prototype。
这样,子类Computer就可以通过原型链访问到父类的属性。
3.3 缺点四、原型式继承function Computer(){    Book.apply(this, arguments);}Computer.prototype = Object.create(Book.prototype);Computer.prototype.constructor = Computer;Computer.prototype.init = function(option){    option.classify = 'computer';    Book.prototype.init(option);};Computer.prototype.say = function(){    console.log('I\'m '+ this.name);}复制代码这里的改进:是使用Object.create(Book.prototype)。它的作用是返回一个继承自原型对象Book.prototype的新对象。且该对象下的属性已经初始化。用Object.create生成新对象,并不会调用到Book的构造函数。这种方式,也可以通过原型链实现继承。
五、Object.create的简单版兼容由于低版本的浏览器是不支持Object.create的。所以这里简单介绍下兼容版本:
Object.create = function(prototype){    function F(){}    F.prototype = prototype;    return new F();}复制代码原理是定义一个空的构造函数,然后修改其原型,使之成为一个跳板,可以将原型链传递到真正的prototype。
六、函数化继承上述两种实现方式,都存在一个问题:不存在私有属性和私有方法。也就是说,存在被篡改的风险。接下来就用函数化来化解这个问题。
function book(spec, my){    var that = {};    // 私有变量    spec.name = spec.name || ''; // 书名    spec.page = spec.page || 0; // 页数    spec.classify = spec.classify || ''; // 类型    var getName = function(){        console.log(spec.name);    };    var getPage = function(){        console.log(spec.page);    };    var getClassify = function(){        console.log(spec.classify);    };    that.getName = getName;    that.getPage = getPage;    that.getClassify = getClassify;    return that;}function computer(spec, my){    spec = spec || {};    spec.classify = 'computer';    var that = book(spec, my);    var say = function(){        console.log('I\'m '+ spec.name);    };    that.say = say;    return that;}var Ninja = computer({name: 'JavaScript忍者秘籍', page: 350});复制代码函数化的优势,就是可以更好地进行封装和信息隐藏。
也许有人疑惑为什么用以下这种方式声明和暴露方法:
var say = function(){    console.log('I\'m '+ spec.name);};that.say = say;复制代码其实是为了保护对象自身的完整性。即使that.say被外部篡改或破坏掉,function computer内部的say方法仍然能够正常工作。另外,解释下that、spec和my的作用:
七、ES6继承最后,看下现代版ES6的类继承。不禁感慨以前的刀耕火种,是多么折磨人
作者: wuqiong    时间: 2018-7-31 10:28

作者: 不二晨    时间: 2018-7-31 11:54
奈斯,很赞
作者: 梦缠绕的时候    时间: 2018-7-31 11:56





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2