一、class概念
es5中,生成实例对象是通过构造函数,实例自身属性和继承方法是分开写的,容易让新手困惑。es6中,引入了class概念,通过关键字class创造类,这种写法更清晰、更像面向对象编程。这是一种语法糖,大部分功能都可以由es5模拟。
class写法:
(1)constructor方法,构造函数,接受参数,给实例添加属性与方法,使用new操作符生成实例时,如果没有constructor方法,系统会默认添加一个空方法。
(2)原型上的方法,方法与方法之间不用逗号隔开,相当于写在construcor.prototype上的方法。所有类的内部方法都是不可枚举的(Object.defineProperty定义enumerable为false),这一点与es5中原型方法有区别。
class Super {constructor(x, y){this[x] = x,this[y] = y;}compute(...args){return args.reduce((res,item) => item + res,0)}get myName(){return 'getter'}set myName(val){return 'setter:' + val}}let superInstance = new Super('name', 'age');console.log(Object.keys(Super.prototype), Object.getOwnPropertyNames(Super.prototype))// => [], ["constructor", "compute"]
tip:**class不实用new调用会报错**,传统的构造函数不用new操作符也能调用(底层代码会检查this对象是否为构造函数的实例,instanceof)。<br />(3)class原型上也可以写存取值方法,用来劫持实例属性的访问与修改,这是写在原型constructor.prototype上的方法,且是存在属性描述对象上的 prop in descriptor = > true<br />(4)class内部可以直接通过类名访问到该类。
class Super{getClass(){return Supber.name}}
注意点:
(1)严格模式,es6的class中默认就是严格模式,无需再写字符串声明严格模式(构造函数中已经添加了 ‘use strict’)。
(2)class不存在函数提升,声明前使用会报错,子类必须在父类后声明(class类是一个通过var声明的函数表达式)。
(3)name属性,class也是一种构造函数的包装,name属性总是返回class后的名字。
(4)class中,this默认指向实例,但是单独引用,或者作为其他对象方法调用,this指向会改变。
class Super{printName(txt){console.log(this.print(`hello ${txt}`))}print(text){console.log(text)}}let {printName} = new Super();printName('三点几嘞') // this => undefined
解决方法:可以在构造函数中,给实例添加bind this后的原型对象方法,或者使用箭头函数。
class Super{constructor(){this.printName = this.printName.bind(this)this.printName2 = ()=> this.printName}printName(txt){console.log(this.print(`hello ${txt}`))}print(text){console.log(text)}}
<br />(5)通过static添加**静态方法**:放在类上的函数(不是原型上),所以不会被实例继承,静态方法里的this指向类,不是实例。
class Super{static print(){this.bite()}static bite(){console.log('wnagwangwang!')}}
子类可以继承父类的静态方法,可以直接通过子类调用,也可以通过子类静态方法中super调用
class Super{static SuperFoo(){console.log("I'm your papa")}}class Son extends Super {static bite(){super.SuperFoo()}}Son.SuperFoo()Son.bite()
(6)实例属性新写法<br />除了在constructor中写实例属性,还可以在class中最顶层写,= 赋值操作,这种写法,一眼就能看出来是实例的属性。
class Super{name = 'your papa'}let instance = new Super();console.log(instance.name)
(7)类的静态属性
class Super{static name = 'GodFather'}console.log(Super.name)
(8)new.target在函数中使用,返回new操作符作用于的构造函数。可以写出只能用于继承,不能实例化的类
class forExtending {consctructor(){if(new.target === forExtending){throw Error('本类不能实例化')}}}
子类继承自父类,父类中的new.target指向父类。
class Super{constructor(){console.log(new.target === Super) // => false}}class Son extends Super {constructor(){super()}}let son = new Son()
二、class继承
ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法,super作为函数调用时,代表父类的构造函数),然后再用子类的构造函数修改this。
