array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 ES6中的类继承和ES5中的继承模式详解 - 爱码网

1、ES5中的继承模式

我们先看ES5中的继承。

既然要实现继承,首先我们得要有一个父类。

Animal.prototype.eat = function(food) {
    console.log(this.name + '正在吃' + food);            
}
function Animal(name) {
    this.color = ['green','red','blue'];
    this.name = name || 'animal';
    this.sleep = function() {
        console.log(this.name + "正在睡觉")
    }
}

1.1、原型链继承

原型链继承核心: 将父类的实例作为子类的原型。

function Cat(name) {
    this.name = name
    this.color = ['green','red','blue'];//引用类型值,,所有实例会共享这个属性。
}
Cat.prototype = new Animal();
var cat = new Cat('cat');
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat instanceof Animal);
console.log(cat.sleep());

原型链式继承模式实现了子类对父类的原型的继承。

但是,原型链式继承并没有实现代码的复用,一些共同的属性:如name,在子类中还是得重新写一遍(即同一套代码还是得重新写)。

再者,cat继承了Animal实例的所有属性和方法,这些方法并不都是我们需要的,也就是过多的继承了没有用的属性。且如果原型中包含引用类型值,那么所有的实例会共享这个属性。

1.2、构造函数模式

构造函数模式核心: 在子类型构造函数的内部调用超类型构造函数。

function Person(name,age,sex){
    this.name = name;
    this.age = age;
    this.sex = sex;
}
function Student(name,age,sex){
    Person.call(this,name,age,sex);
    this.grade = grade;
}
let student = new Student;

优点:

  • 构造函数模式继承实现了代码的复用

缺点:

  • 不能继承借用的构造函数的原型,只能借用构造函数本身的属性和方法
  • 每次构造函数都要多走一个函数

1.3、组合继承

实现核心:组合继承结合了上面两种方式的继承模式,即实现了代码复用,也实现呢了原型继承。

function SuperType(name) {
    this.name = name;
    this.colors = ['red','blue','pink'];
}
SuperType.prototype.sayName = function() {
    console.log(this.name);
}
function SubType(name,age) {
    //继承属性
    SuperType.call(this,name);//在创建实例时第二次调用SuperType
    this.age = age;
}

//继承方法
SubType.prototype = new SuperType();//第一次调用SuperType
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
    console.log(this.age)
}

缺点:

  • 父类构造函数被调用2次,子类实例的属性存在两份,一份在原型上,一份在实例属性上。造成内存的浪费。

1.4、寄生组合式继承

寄生组合式继承是对组合继承的进一步优化。我们先看一下为什么要写这个语句。

SubType.prototype = new SuperType();

我们无非是想让SubType继承SuperType的原型。但是我们为什么不直接写成这样呢?

SubType.prototype = SuperType.prototype

这样写确实可以实现子类对象对父类对象原型的继承。但是这样写的话:所有继承该父类的子类对象的原型都指向同一个了。也就是说SubType不能有自己的原型了。这显然不是我们想要的。

既然不能直接继承,那可不可以间接继承SuperType.prototype呢。这就是最终的解决方案:寄生组合式继承

我们让一个函数去指向SuperType.prototype,然后让SubType.prototype指向这个函数产生的对象不就可以了嘛。

function inherit(Target,Origin) {//实现寄生组合式继承的核心函数
    function F() {};
    F.prototype = Origin.prototype; //F()的原型指向的是Origin
    Target.prototype = new F(); //Target的原型指向的是F()
    Target.prototype.constructor = Target; 
SubType.prototype.__proto__ == SuperType.prototype }
function SuperType(name) { this.name = name; this.colors = ['red','blue','pink']; } SuperType.prototype.sayName = function() { console.log(this.name); } function SubType(name,age) { //继承属性 SuperType.call(this,name);//在创建实例时第二次调用SuperType this.age = age; } inherit(SubType,SuperType);//实现寄生组合式继承

我们再来看一下实现寄生组合式继承的核心函数。F函数其实是通用的,我们没必要每次进入inherit函数时都声明一遍。所以我们可以用闭包的形式来写:

var inherit = (function () {
        var F = function () {};
        return function (Target , Origin) {
            F.prototype = Origin.prototype;//F()的原型指向的是Origin
            Target.prototype = new F();//Target的原型指向的是F()
            Target.prototype.constructor = Target;
            Target.prototype.uber = Origin.prototype;
SubType.prototype.__proto__ == SuperType.prototype } })()

2、ES6中的类继承

我们先来看一下ES6里面是如何定义一个类的。

class Parent {
    constructor(name,age) {
        this.name = name;
        this.age = age;
    }
    
    getName() {
        return this.name;
    }
}
typeof Parent; //function,类的数据类型就是函数,类本身就指向构造函数

上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。也就是说,ES5的构造函数Parent,对应ES6的Parent类的构造方法。
Parent类除了构造方法,还定义了一个getName方法。

注意,定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去就可以了。另外,方法之间不需要逗号分隔,加了会报错。类中定义的所有方法都是不可枚举的。

此外:类的所有方法都定义在类的prototype属性上面。且class不存在变量提升,如果在class声明之前调用,会报错。

new Parent();
class Parent {
    constructor(name,age) {
        this.name = name;
        this.age = age;
    }
    
    getName() {
        return this.name;
    }
}
//Uncaught ReferenceError: Parent is not defined

2.1、类的constructor方法

constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,

如果没有显式定义,一个空的constructor方法会被默认添加

2.2、类的继承

class Child extends Parent {
    constructor(sex) {
        super();
        this.sex = sex;
        
    }
}
var child = new Child('xiaoyu',12,'man');

在子类的构造函数中,如果显示声明了constructor,则必须要显示的调用super函数(这一点和Java有点不一样)。

只有调用super之后,才可以使用this关键字,否则会报错。

2.3、类的prototype属性和__proto__属性

大多数浏览器的ES5实现之中,每一个对象都有__proto__属性,指向对应的构造函数的prototype属性。

Class作为构造函数的语法糖,同时有 prototype属性和__proto__属性,因此同时存在两条继承链。

  • 子类的__proto__属性,表示类的继承,总是指向父类。
  • 子类prototype属性,表示类的实例的继承,类的实例的__proto__属性总是指向类的prototype属性。

这些特点和ES5的寄生组合式继承完全一致,所以类的继承可以看做是寄生组合式继承的语法糖(简单理解)。但实际上两者实现的底层原理是完全不一样的。因为阮一峰大大的书籍《ES6入门基础》里面认为ES6的继承机制完全和ES5的继承机制不同。阮一峰大大的书是这么说的。

ES5的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6的继承机制完全不同,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。

所以对这方面有深入理解的小伙伴们可以说说自己的理解。共同进步。

先写到这里,后面如果有更多的理解再继续添加。

相关文章: