一、class概念

    es5中,生成实例对象是通过构造函数,实例自身属性和继承方法是分开写的,容易让新手困惑。es6中,引入了class概念,通过关键字class创造类,这种写法更清晰、更像面向对象编程。这是一种语法糖,大部分功能都可以由es5模拟。
    class写法:
    (1)constructor方法,构造函数,接受参数,给实例添加属性与方法,使用new操作符生成实例时,如果没有constructor方法,系统会默认添加一个空方法。
    (2)原型上的方法,方法与方法之间不用逗号隔开,相当于写在construcor.prototype上的方法。所有类的内部方法都是不可枚举的(Object.defineProperty定义enumerable为false),这一点与es5中原型方法有区别。

    1. class Super {
    2. constructor(x, y){
    3. this[x] = x,
    4. this[y] = y;
    5. }
    6. compute(...args){
    7. return args.reduce((res,item) => item + res,0)
    8. }
    9. get myName(){
    10. return 'getter'
    11. }
    12. set myName(val){
    13. return 'setter:' + val
    14. }
    15. }
    16. let superInstance = new Super('name', 'age');
    17. console.log(Object.keys(Super.prototype), Object.getOwnPropertyNames(Super.prototype))
    18. // => [], ["constructor", "compute"]
    1. tip:**class不实用new调用会报错**,传统的构造函数不用new操作符也能调用(底层代码会检查this对象是否为构造函数的实例,instanceof)。<br />(3class原型上也可以写存取值方法,用来劫持实例属性的访问与修改,这是写在原型constructor.prototype上的方法,且是存在属性描述对象上的 prop in descriptor = > true<br />(4class内部可以直接通过类名访问到该类。
    1. class Super{
    2. getClass(){
    3. return Supber.name
    4. }
    5. }

    注意点:
    (1)严格模式,es6的class中默认就是严格模式,无需再写字符串声明严格模式(构造函数中已经添加了 ‘use strict’)。
    (2)class不存在函数提升,声明前使用会报错,子类必须在父类后声明(class类是一个通过var声明的函数表达式)。
    (3)name属性,class也是一种构造函数的包装,name属性总是返回class后的名字。
    (4)class中,this默认指向实例,但是单独引用,或者作为其他对象方法调用,this指向会改变。

    1. class Super{
    2. printName(txt){
    3. console.log(this.print(`hello ${txt}`))
    4. }
    5. print(text){
    6. console.log(text)
    7. }
    8. }
    9. let {printName} = new Super();
    10. printName('三点几嘞') // this => undefined

    解决方法:可以在构造函数中,给实例添加bind this后的原型对象方法,或者使用箭头函数。

    1. class Super{
    2. constructor(){
    3. this.printName = this.printName.bind(this)
    4. this.printName2 = ()=> this.printName
    5. }
    6. printName(txt){
    7. console.log(this.print(`hello ${txt}`))
    8. }
    9. print(text){
    10. console.log(text)
    11. }
    12. }
    1. <br />(5)通过static添加**静态方法**:放在类上的函数(不是原型上),所以不会被实例继承,静态方法里的this指向类,不是实例。
    1. class Super{
    2. static print(){
    3. this.bite()
    4. }
    5. static bite(){
    6. console.log('wnagwangwang!')
    7. }
    8. }
    1. 子类可以继承父类的静态方法,可以直接通过子类调用,也可以通过子类静态方法中super调用
    1. class Super{
    2. static SuperFoo(){
    3. console.log("I'm your papa")
    4. }
    5. }
    6. class Son extends Super {
    7. static bite(){
    8. super.SuperFoo()
    9. }
    10. }
    11. Son.SuperFoo()
    12. Son.bite()
    1. 6)实例属性新写法<br />除了在constructor中写实例属性,还可以在class中最顶层写,= 赋值操作,这种写法,一眼就能看出来是实例的属性。
    1. class Super{
    2. name = 'your papa'
    3. }
    4. let instance = new Super();
    5. console.log(instance.name)
    1. 7)类的静态属性
    1. class Super{
    2. static name = 'GodFather'
    3. }
    4. console.log(Super.name)
    1. 8new.target在函数中使用,返回new操作符作用于的构造函数。可以写出只能用于继承,不能实例化的类
    1. class forExtending {
    2. consctructor(){
    3. if(new.target === forExtending){
    4. throw Error('本类不能实例化')
    5. }
    6. }
    7. }
    1. 子类继承自父类,父类中的new.target指向父类。
    1. class Super{
    2. constructor(){
    3. console.log(new.target === Super) // => false
    4. }
    5. }
    6. class Son extends Super {
    7. constructor(){
    8. super()
    9. }
    10. }
    11. let son = new Son()

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