彻底搞懂ES6中的Class(全面解析)

2020-01-2119:04:34WEB前端开发Comments4,625 views字数 3455阅读模式

ES6中的class你会想到什么呢?可能有的小伙伴只是知道它,或许用过一两次,没关系,这次我们从头开始,带你体验class的铁汉柔情(强大和优雅);文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

跟往常一样,我们需要带着三个问题去看这篇文章:what?how? where?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html


什么是Class

使用react的小伙伴都知道,最初学习使用react框架的时候,首先了解的就是通过class来书写组件,所以,通过阅读这篇文章,也是为学习react打一个重要的基础!让我们先看一个class标准的写法吧:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

   class Point {
       constructor (x, y) {
           this.x = x
           this.y = y
       }
       MyName () {
           return (`我的名字叫${this.x}${this.y}!`)
       }
   } 
   let getName = new Point('f', 'zh');
   getName.MyName()   // 我的名字叫fzh
复制代码

通过上面的代码可以看出这个class的写法,与ES5中构造函数的写法很相似,没错,class就是构造函数的语法糖(可以理解成class就是构造函数的另一种写法),使用的时候,也是直接对class(类)使用new命令,跟构造函数的用法完全一致;考虑到有的同学不太明白上面写的啥,在这里解释一下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

  1. 首先声明了一个名字为Point的class,换做ES5的写法就是 function Point ( ) { }
  2. class里面写的方法,最终都定义在了 class 的原型上,换做ES5的写法就是:Point.prototype.MyName = function ( ) { }
  3. constructor 方法就是构造方法,里面的 this 代表实例对象,constructor 属性,直接指向“类”的本身;
  4. constructor 是class的默认方法,通过 new 命令生成对象实例时,自动调用 constructor ,即使没有定义 constructor ,也会默认有一个空的 constructor

它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已,光说无用,让我们来证明一下吧:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

  // 接上面代码
  console.log(typeof Point);   // "function"
  console.log(Point === Point.prototype.constructor);   // true
复制代码

这段代码表明了类的数据类型就是函数,类的本身就是指向构造函数;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

本段需要注意的地方如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

  • class内部定义的方法都是不可枚举的;
  • 生成类的写法需使用 new 命令,否则会报错;
  • constructor 方法默认返回实例对象(即 this );
  • 类和模块的内部,默认就是严格模式,所以不需要使用 use strict 指定运行模式;
  • 类不存在变量提升;
  • 类的方法内部如果含有this,它默认指向类的实例;

以上就是class的基本知识,如果理解了上面的内容,那么恭喜你,可以放心的在你代码中使用class了!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

彻底搞懂ES6中的Class(全面解析)

class进阶知识

开头咱们说到过class是强大和优雅的,那么它到底强大在哪?又优雅在哪呢?我怎么读现在还没有看出来呢?好,让我们带着这两个疑问去下面的文章寻找答案!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

class静态方法

类相当于实例的原型,所有在类中定义的方法都会被实例继承,如果不想让你定义的方法被实例继承,也很简单,只需要在方法前面加上 static 关键字,就表示该方法不会被实例继承,而且直接通过类就可以调用,这也称为 静态方法 ,看下面代码:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

 class MyStatic {
     static classMsg () {
         return ("My name is feng zhihao");
     }
 }
 
 // 因为"classMsg"定义方法名称之前加了 'static' 关键字
 // 所以该方法是一个静态方法
 Mystatic.classMsg();  // "My name is feng zhihao"
 
 let foo = new Mystaic();
 foo.classMsg(); // TypeError: foo.classMsg is not a function
复制代码

上面代码表明:静态方法可以直接在类上调用,而不是在类的实例上调用,如果在实例上调用的话,就会抛出错误,表示不存在该方法;扩展一下,父类的静态方法可以被子类继承:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

class Fzh {
    static classMsg () {
        return (`新春快乐,鼠你最棒`);
    }
}

class Ibas extends Fzh {}

Ibas.classMsg();  // "新春快乐,鼠你最棒"`
复制代码

new.taeget属性

new 是从构造函数生成实例的命令,ES6为 new 命令引入了 new.target 属性,如果构造函数不是通过 new 命令调用的,那么 new.target 会返回 undefined,在 class 内部调用 new.taeget ,返回是当前class,需要注意的是:子类继承父类时,new.target 会返回子类:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

 // " 返回当前class "
 class Register {
     constructor (x) {
         console.log(new.taeget === Register);
         this.x = x;
     }
 }
 
 // 返回的是true,说明new.target返回的是当前的class
 let RegClass = new Register("hello")  // true
复制代码
// "父类调用new.target返回子类"

class Register {
    constructor () {
        console.log(new.target === Register);
    }
}

class Square extends Register {
    constructor (x) {
        super(x, x);
    }
}

let sole = new Square(1);    // false(new.target返回的是子类)

复制代码

super关键字

读到这,是不是觉得初学react的时候就是在学习class呢,尤其是 extendssuper关键字,我们会经常碰到它们的身影,其实super这个关键字既可以当做函数使用,也可以当做对象使用,在这两种情况下,它的作用完全不同:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

第一种情况: 做为函数时,super只能用在子类的构造函数中,用在其他地方会报错;当调用super时,它代表父类的构造函数 ( 这是规定 ) ,ES6还规定了子类的构造函数必须执行一次super函数;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

接下来的说法可能比较绕,建议读完一遍然后看一遍代码,再回过头读一遍效果会更好:super虽然代表父类,但是它返回的是子类的实例,也就是说super内部的this是指向子类的,证明一下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

class Supe {
    constructor () {
        console.log(new.target.name);
    }
}

class SonSupe extends Supe {
    constructor () {
        super();
    }
}

new Supe();   // Supe
new SonSupe();  // SonSupe
复制代码

从上面代码可以看出,new.target指的是当前正在执行的函数,在 super 执行时,它指向的是子类 SonSuper 的构造函数,而不是父类 Supe 的构造函数,也就是说,super() 内部的this是指向子类的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

第二种情况: super作为对象时,在普通方法中指向父类的原型对象,在静态方法中指向父类,由于 super 指向的是父类的原型对象,所以定义在父类实例上的方法或属性是无法通过 super 调用的:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

class A {
    gain () {
        return ("欢迎大佬指出不足,我绝对不会改~");
    }
}

class B extends A {
    constructor () {
        super();
        console.log(super.gain());   // "欢迎大佬指出不足,我绝对不会改~"
    }
}

复制代码

从上面代码可以看出super指向父类的prototype ,所以 super.gain() 等同于 A.prototype.gain() ,ES6规定:通过 super 调用父类方法时,super 会绑定子类的 this文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html


结尾

这篇文章主要讲了ES6中 class 的语法和小细节,我们需要做的就是记住这些知识点,真真正正的去理解它们,不断的练习与尝试,日后才能灵活的去运用到开发中,另外,推荐大家去看一下阮一峰出版的《ES6标准入门》这本书,最后祝小伙伴们新春快乐,永无Bug! 哦了,散会!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

作者:冯智豪
链接:https://juejin.im/post/5e174823e51d451c52192e7f
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html

文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/17761.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/gcs/17761.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定