专栏首页前端技术总结小结ES6基本知识点(三):类与继承
原创

小结ES6基本知识点(三):类与继承

0,本文适合人群和主要内容

ES6初学者,通过阅读本文可对ES6知识点有个大体的概念,强烈建议阅读阮一峰大大的ES6入门。

老司机可以直接绕路。

上一节主要是总结了Symbol、Set和Map的有关内容。本节要总结ES6中的类、类的继承的有关内容。

1,类

ES5中没有类的概念,只能通过构造函数来初始化对象实例。ES6中可以通过class关键字来定义类。

ES5实现

function Person(name){
    this.name = name;
}
Person.prototype.hello = function(){
    console.log('Hi',this.name)
}
var person1 = new Person('Peter');
person1.hello(); // Hi Peter
console.log(person1 instanceof Person) // true
console.log(person1 instanceof Object) // true

说明:

先创建一个构造函数Person,然后定义一个方法hello,并赋值给这个构造函数的原型。这样构造函数的所有实例都将共享这个方法。再通过new操作符得到一个实例person1,该实例可以调用hello方法。并且通过instanceof可以看出:该实例person1是构造函数Person的实例、也是对象Object的实例。

ES6实现

通过class关键字声明一个类,上述代码的ES6等价版本:

class Person{
    constructor(name){
        this.name = name
    }
    hello(){
        console.log('Hi',this.name)
    }
}
person1 = new Person('Peter');
person1.hello(); // Hi Peter
console.log(person1 instanceof Person) // true
console.log(person1 instanceof Object) // true

说明:

在定义Person类中,先定义constructor方法,这个方法等价于定义Person构造函数。然后在类中直接定义hello方法,这等价于往构造函数的原型上添加方法,即hello方法是添加到Person.prototype属性上。

class Person {
    // 等价于定义Person构造函数
    constructor(name) {
        this.name = name
    }
    // 等价于Person.prototype.hello
    hello() {
        console.log('Hi', this.name)
    }
}
person1 = new Person('Peter');
person1.hello(); // Hi Peter

几点要注意的地方

(1)ES6中的类是语法糖,本质还是函数,一个具有构造函数方法行为的函数;

例如上述例子中:

 console.log(typeof Person) // function

(2)类中通过constructor方法来定义构造函数,在用new关键字初始化实例时自动执行。并且,一个类必须显示定义constructor方法,如果没有,则会默认添加一个空的constructor方法。

class Person{
    // 没有定义constructor方法
}

// 等价于

class Person{
    constructor(){}
}

(3)类声明不能被提升,就像let声明不能被提升;

// Uncaught ReferenceError: Person is not defined
let person1 = new Person('Peter');
class Person {
    constructor(name) {
        this.name = name;
    }
    hello() {
        console.log('Hi', this.name)
    }
} 

(4)类中定义方法时,不需要function关键字,写法是:方法名(){xxx}这种形式;并且各方法之间不要逗号分隔;

(5)类的名称只在类中为常量,因此在定义类的方法中是不能修改类的名称的,不过可以在声明类之后修改;

内部修改类名会报错:

class Person{
    constructor(){
        Person = "OterPerson"
    }
}
let person2 = new Person(); // Uncaught TypeError: Assignment to constant variable.

(6)类中的所有方法都是添加到类的原型上,即类的prototype属性上,并且都是不可枚举的,可以通过Object.keys()查看;

验证:

class Person {
    constructor(name) {
        this.name = name
    }
    hello() {
        console.log('Hi', this.name)
    }
}
console.log(Person.prototype);
console.log(Object.keys(Person.prototype)); // []
console.log(Object.getOwnPropertyNames(Person.prototype)); // ["constructor", "hello"]

补充:

Object.keys(obj) 

返回给定对象obj的所有可枚举属性的字符串数组

Object.getOwnPropertyNames(obj)

返回给定对象obj的所有属性的字符串数组

(7)调用类的构造函数,要通过new调用,不用new则会报错

验证:

class Person {
    constructor(name) {
        this.name = name;
    }
    hello() {
        console.log('Hi', this.name)
    }
}
let person1 = Person('Peter'); // Uncaught TypeError: Class constructor Person cannot be invoked without 'new'

(8)类的name属性,就是class关键字后面的标识符。

class Person {
    constructor(name) {
        this.name = name;
    }
    hello() {
        console.log('Hi', this.name)
    }
}
console.log(Person.name) // Person

(9)new.target

在类的构造函数中使用new.target,一般情况下,new.target等于类的构造函数

验证:

class Person {    
    constructor(name) {
        this.name = name;
        console.log(new.target === Person)
    }
    hello() {
        console.log('Hi', this.name)
    }
}
let person1 = new Person('Peter') // true

2,继承

引用:

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

ES5实现继承

function Parent(value) {
    this.value = value;
}
Parent.prototype.printValue = function () {
    return this.value
}
function Child(value) {
    Parent.call(this, value);
}
Child.prototype = Object.create(Parent.prototype, {
    constructor: {
        value: Child,
        enumerable: false,
        writable: true,
        configurable: true
    }
});
var child1 = new Child('Peter');
console.log(child1)
console.log(child1.printValue()); // Peter
console.log(child1 instanceof Child); // true
console.log(child1 instanceof Parent); // true

说明:

要Child继承Parent,就用一个从Parent.prototype创建的新对象重写Child的原型child.prototype,并且调用Parent.call()方法,child1:

ES6实现继承

使用extends关键字实现继承,通过调用super()可以访问基类的构造函数

上述代码的ES6等价版本:

class Parent {
    constructor(value) {
        this.value = value;
    }
    printValue() {
        return this.value
    }
}
class Child extends Parent {
    constructor(value) {
        // 等价于 Parent.call(this,value)
        super(value)
        this.value = value
    }
}
let child1 = new Child('Peter');
console.log(child1.printValue()); // Peter
console.log(child1 instanceof Child) // true 
console.log(child1 instanceof Child) // true

几点要注意的地方

(1)使用extends关键字即可实现继承,更符合面向对象的编程语言的写法

(2)关于super():

--只可以在子类的构造函数中使用super,其他地方使用会报错;

验证,在非子类中使用super(),会报错:

// Uncaught SyntaxError: 'super' keyword unexpected here
class Parent {
    constructor(value) {
        super(value);
        this.value = value;
    }
    printValue() {
        return this.value
    }
}

--在子类中指定了构造函数则必须调用super(),否则会报错。因为super负责初始化this,如果在调用super()前使用this,则会报错;

验证:

// Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
class Parent {
    constructor(value) {
        this.value = value;
    }
    printValue() {
        return this.value
    }
}
class Child extends Parent {
    constructor(value) {
        this.value = value
    }
}
let child1 = new Child('Peter');

--如果子类中没定义构造函数,则创建子类实例时,会自动调用super(),并且传入所有参数。

class Child extends Parent {
    // 没有构造函数
}

// 等价于

class Child extends Parent {
    constructor(...args) {
        super(...args)
    }
}

(3)子类也会继承父类的静态方法(static)

(4)关于new.target

如果是子类继承了父类,则父类中的new.target是子类的构造函数:

验证:

// 定义父类
class Rectangle{
    constructor(length,width){
        console.log(new.target === Rectangle) // false
        console.log(new.target === Square) // true
        this.length = length;
        this.width = width;
    }
}
// 定义子类
class Square extends Rectangle{
    constructor(length){
        super(length,length);
    }
}
let square1 = new Square(5); 

3,小结

本文主要通过对比ES5的实现方法,分别总结了ES6中类和类的继承的有关基本知识。如有问题,欢迎指正。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 小结ES6基本知识点(一)

    ES6初学者,通过阅读本文可对ES6知识点有个大体的概念,强烈建议阅读阮一峰大大的ES6入门。

    前端林子
  • 小结ES6基本知识点(二)

    ES6初学者,通过阅读本文可对ES6知识点有个大体的概念,强烈建议阅读阮一峰大大的ES6入门。

    前端林子
  • 小结ES6基本知识点(四):数组的扩展

    ES6初学者,通过阅读本文可对ES6知识点有个大体的概念,强烈建议阅读阮一峰大大的ES6入门

    前端林子
  • 小结ES6基本知识点(五):对象的扩展

    ES6初学者,通过阅读本文可对ES6知识点有个大体的概念,强烈建议阅读阮一峰大大的ES6入门

    前端林子
  • 小结ES6基本知识点(六):模块的语法

    ES6初学者,通过阅读本文可对ES6知识点有个大体的概念,强烈建议阅读阮一峰大大的ES6入门。

    前端林子
  • 我的 Web 前端面试经历——百度

    面试是个漫长的过程,从海投到收获电话面试,一面、二面、三面,一个步骤出错那么后面就宣告终结。同时,面试过程中你也可能会遇到一些面试官的刁难,甚至部分面试官会说些...

    李才哥
  • 前端-如何继承 Date 对象?由一道题彻底弄懂 JS 继承

    于是,随手用JS中经典的组合寄生法写了一个继承,然后,刚准备完美收工,一运行,却出现了以下的情景:

    grain先森
  • 面试官问:JS的继承

    用过 React的读者知道,经常用 extends继承 React.Component。

    若川
  • 小结BFC的基本知识与应用

    在写css样式时,可能是添加了一个样式后就达到了预期效果。有没有想过,是我们在不经意间触发了什么,帮助我们达到了效果?本文就快速介绍下css样式中经常使用的BF...

    前端林子
  • 十六、半小时掌握ES6常用知识,覆盖80%实践场景

    在实际开发中,ES6已经非常普及了。掌握ES6的知识变成了一种必须。尽管我们在使用时仍然需要经过babel编译。

    用户6901603
  • JS 继承

    用过 React的读者知道,经常用 extends继承 React.Component:

    grain先森
  • 从零开始学 Web 系列教程

    在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识点,期间也会分享一些好玩的项目。现在就让我们一起进入 Web 前端学习的冒险之旅吧!

    Daotin
  • 小白入门学习web前端,这些干货不能少

    入门级别指的是了解什么是前端(前端到底是什么其实很多人还是不清楚的),了解基本的html、css和javascript语法(这些语方面的东西网上随便搜一下就有很...

    用户5827212
  • Design Pattern: Not Just Mixin Pattern

    Brief                                 从Mix-In模式到Mixin模式,中文常用翻译为“混入/织入模式”。单纯从名字上看...

    ^_^肥仔John
  • 每个JavaScript工程师都应懂的33个概念

    这个项目是为了帮助开发者掌握 JavaScript 概念而创立的。它不是必备,但在未来学习(JavaScript)中,可以作为一篇指南。

    Fundebug
  • 适合 JS 新手学习的开源项目——在 GitHub 学编程

    这里是 HelloGitHub 的《GitHub 上适合新手的开源项目》系列的最后一篇,系列文章:

    HelloGitHub
  • 「思维导图学前端 」一文搞懂Javascript对象,原型,继承

    去年开始我给自己画了一张知识体系的思维导图,用于规划自己的学习范围和方向。但是我犯了一个大错,我的思维导图只是一个全局的蓝图,而在学习某个知识点的时候没有系统化...

    Tusi
  • 【前端词典】继承

    继承于我们前端来说绝对是非常熟悉也必须熟悉的一个高频必懂知识点。熟悉到只要是面试一定会有关于继承的问题;而且源码中继承的使用也随处可见。

    小生方勤
  • PHP数组基本用法与知识点总结

    索引数组: 指键名为整数的数组。默认情况下,索引数组的键名是从0开始,并依次递增。它主要适用于利用位置来标识数组元素的情况。另外,索引数组的键名也可以自己指定

    砸漏

扫码关注云+社区

领取腾讯云代金券