ES6 Class 继承

667 阅读4分钟

前言

传统的javascript中只有对象,没有类的概念。它是基于原型的面向对象语言。原型对象特点就是将自身的属性共享给新对象。这样的写法相对于其它传统面向对象语言来讲,独树一帜也可以说难以接受!

三大特性

封装 继承 多态性

ES5中的类

ES5中如果要生成一个对象实例,需要先定义一个构造函数,然后通过new操作符来完成
示例:

//构造函数名大写(非强制,但这么写有助于区分构造函数和普通函数)
function Person(name,age) {
    this.name = name;
    this.age=age;
}
Person.prototype.say = function(){
    return "我的名字叫" + this.name+"今年"+this.age+"岁了";
}
var obj=new Person("tom",88);//通过构造函数创建对象,必须使用new 运算符
console.log(obj.say());//我的名字叫tom今年88岁了

构造函数生成实例的执行过程:

1.当使用了构造函数,并且new 构造函数(),后台会隐式执行new Object()创建对象;
2.将构造函数的作用域给新对象,(即new Object()创建出的对象),而函数体内的this就代表new Object()出来的对象。
3.执行构造函数的代码。
4.返回新对象(后台直接返回);

ES6中的类

ES6引入了class(类)这个概念,通过class关键字可以定义类。该关键字的出现使得javascript在对象写法上更加清晰,更像是一种面向对象的语言。

之前的代码改为ES6的写法:

class Person{//定义了一个名字为Person的类
    constructor(name,age){//constructor是一个构造方法,用来接收参数
        this.name = name;//this代表的是实例对象
        this.age = age;
    }
    say(){//这是一个类的方法,注意千万不要加上function
        return "我的名字叫" + this.name+"今年"+this.age+"岁了";
    }
}
var obj=new Person("laotie",88);
console.log(obj.say());//我的名字叫laotie今年88岁了

由下面代码可以看出类实质上就是一个函数。类自身指向的就是构造函数。所以可以认为ES6中的类其实就是构造函数的另外一种写法!

console.log(typeof Person);//function
console.log(Person===Person.prototype.constructor);//true

以下代码说明构造函数的prototype属性,在ES6的类中依然存在着。
console.log(Person.prototype);//输出的结果是一个对象
实际上类的所有方法都定义在类的prototype属性上。代码证明下:

Person.prototype.say=function(){//定义与类中相同名字的方法。成功实现了覆盖!
    return "我是来证明的,你叫" + this.name+"今年"+this.age+"岁了";
}
var obj=new Person("kity",88);
console.log(obj.say());//我是来证明的,你叫kity今年88岁了

当然也可以通过prototype属性对类添加方法。如下:

Person.prototype.addFn=function(){
    return "我是通过prototype新增加的方法,名字叫addFn";
}
var obj=new Person("kity",88);
console.log(obj.addFn());//我是通过prototype新增加的方法,名字叫addFn

还可以通过Object.assign方法来为对象动态增加方法

Object.assign(Person.prototype,{
    getName:function(){
        return this.name;
    },
    getAge:function(){
        return this.age;
    }
})
var obj=new Person("kity",88);
console.log(obj.getName());//kity
console.log(obj.getAge());//88

注意:

//ES5可以先使用再定义,存在变量提升
new A();
function A(){

}
//ES6不能先使用再定义,不存在变量提升 会报错
new B();//B is not defined
class B{

}

ES6中的 class继承

  • 父类(基类)
  • 子类
  • extends 关键字
//class 相当于es5中构造函数
//class中定义方法时,前后不能加function,全部定义在class的prototype属性中
//class中定义的所有方法是不可枚举的
//class中只能定义方法,不能定义对象,变量等
//class和方法内默认都是严格模式
//class声明的类默认首字母大写(不是必须,是为了和方法函数区分开来)
//es5中constructor为隐式属性
//给子类添加属性或者方法的时候必须用super()方法 而且在this之前


//父类
class Person {
  name
  age
  constructor(name, age) {
    this.name = name
    this.age = age
    // console.log(this) //实例化对象
  }

  say() {
    console.log(this) //谁调用就指向谁
    return `我是${this.name},我${this.age}岁`
  }
}

let p1 = new Person('张三', 18) //通过new 实例化对象
p1.say() //我是张三,我18岁


//子类 通过 extends 继承父类
class Son extends Person {
  money
  weight
  constructor(name, age) {
    super(name, age) //通过父类改变this指向,继承父类属性
    this.money = 200 //给子类上添加父类没有的属性
    this.weight = '180kg'
  }

  run() {
    return `我是${this.name},我正在跑步`
  }
}
let p2 = new Son('李四', 20) //实例化对象
console.log(p2.say()) //我是李四,我20岁
console.log(p2.run()) //我是李四,我正在跑步
console.log(p2.money) //200
console.log(p2.weight) // 180kg

注意项:

1.在类中声明方法的时候,千万不要给该方法加上function关键字
2.方法之间不要用逗号分隔,否则会报错
3.`class不存在变量提升`,所以需要先定义再使用。因为`ES6不会把类的声明提升到代码头部`,
但是`ES5`就不一样,`ES5存在变量提升`,可以先使用,然后再定义。