JS之class的前世今生

Javascript之class的前世今生

最早JavaScript中所谓的类,其实是一种设计模式:一个构造函数(consturctor)和一个用于在该类实例间共享属性和方法的原型对象(Objcet.prototype)的结合。为了达到继承,通过函数来模拟类来创建对象。

今天我主要讲讲js类的发展,一是理清class的实质,二是掌握继承extends的实现,三是梳理ES6以前的关于这方面的知识。

ES6 class的前世

(1)创建对象

js引入class的目的,其实就是为了创建对象,这里梳理一下ES6以前创建对象的方式。

一、最基础的new

var friend = new object();
friend .name = "girl";
friend .speak = function(){
    console.log(this.name + "_said:I miss you");
}

二、字面向量

var friend = {
    name: 'girl',
    speak: function(){
        console.log(this.name + "_said:I miss you");
    }
};

方法一、二虽然可以创建对象,但是不易封装复用

三、工厂模式

function friend(name){
  var o = new object();
  o.name = name;
  o.speak = function(){
    console.log(this.name + "_said:I miss you");
  }
  return o;
}

var somebody = new friend("girl");
somebody.speak();

比起一二,friend函数确实是封装了一个属性和一个方法。然而有个问题,这个函数无法解决对象识别问题,就是创造出来的实例如somebody是Object类型,因为o是从Object里new出来的。

四、构造函数

function friend(name){
  this.name = name;
  this.speak = fucntion(){
    console.log(this.name + "_said:I miss you");
  }
}
var somebody = new friend("girl");
somebody.speak();

虽然这个方法解决了三的问题,但还是有缺陷。每次创建friend对象,每个对象都会有一个speak方法,消耗很大。

五、原型封装

function friend(name){
  this.name = name;
}
friend.prototype.speak = function(){
  console.log(this.name + "_said:I miss you");
}

var somebody = new friend("girl");
somebody.speak();

和构造函数不同的,这里通过原型封装的新对象的方法是所有实例都可以共享的。

(2)继承

现在已经能完成创建对象的要求了,但是类还有继承的要求。

六、基于原型链的继承

 
基于原型链的特点,通过将子类构造函数的原型作为父类构造函数的实例,这样就连通了子类-子类原型-父类,原型链的特点就是逐层查找,从子类开始一直往上直到所有对象的原型Object.prototype,找到属性方法之后就会停止查找,所以下层的属性方法会覆盖上层。

方法一:

function friend(name){
  this.name = name;
}

function girlFriend(name){}

girlFriend.prototype = new friend(name);
girlFriend.prototype.constructor = girlFriend;

var a = new girlFriend("L");
console.log(a.name);    //L

1.把子类girlFriend的原型对象指向父类的实例化对象,这样即可以继承父类friend原型对象上的属性和方法 
2.这时子类的constructor属性会指向friend,手动把constructor属性指向子类girlFriend,就可以在父类的基础上添加属性和方法了

方法二:

function friend(name){
  this.name = name;
}

function girlFriend(name){
  friend.call(this,name);
}

var a = new girlFriend("L");
console.log(a.name);    //L

ES6 class的今生

class friend{
    constructor(name) {
        this.name = name; 
    }

    speak() {
        console.log(this.name + "_said:I miss you");
    }
}

class girlFriend extends friend {
    constructor(name) {     
        super(name);        //如果子类中存在构造函数,则需要在使用“this”之前首先调用super()
        this.name = name;
    }

    speak() {
        super.speak();  
    }
}

1.子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。 
2.直接调用super(name),就可以直接继承父类的属性和方法

可对比ES5的两种继承方法理解代码

原文地址:https://www.cnblogs.com/ZpandaZ/p/7397118.html