JavaScript中Class类的基本语法类的继承装饰器1.类的基本语法可以看作是ES5中构造函数的语法糖,其大部分功能都可以在ES5中实现1.1定义一个ES5类functionStudent(name,age){this.name=namethis.age=age}Student.prototype={constructor:Student,showName(){returnthis.name}}ClassclassStudent{constructor(name,age){this.name=namethis.age=age}showName(){returnthis.name}}console.log(Student.prototype);//{constuctorshowName}类的方法constructor和showName都定义在prototype上,并且每个方法之间没有逗号Open1.2构造方法是类的默认方法。如果没有定义,默认添加一个空方法。当使用newclassStudent{constructor(name,age){this.name=namethis.age=age}showName(){returnthis.name}}conststd1=newStudent("ZhangSan")console.log(std1);//{name:"ZhangSan",age:undefined}与ES5不同,定义class没有变量提升,即实例化必须在定义1.3之后私有方法和私有属性只在类内部被调用和使用。方法和属性私有方法constprivate1=Symbol('private1')constprop1=Symbol('prop1')classStudnet{//公共方法foo(parm1,parm2){//内部使用的私有方法this[private1](parm1)private2.call(this,parm2)}//Privatemethod[private1](parm){returnthis[prop1]=parm}}使用Symbol或外部构造函数实现方法内部私有,实例化对象不能访问这些方法私有属性classA{constructor(prop1,prop2){constprop=Symbol('prop')this[prop]=prop1this.age=prop2}}letobj=newClassA(1)console.log(obj[支柱]);//ReferenceErrorconsole.log(obj[(Object.getOwnPropertySymbols(obj)[0])]);//1使用Symbol可以实现一定意义上的私有属性,但是这些属性仍然可以使用Object.getOwnPropertySymbols()访问方法类Studnet{#aconstructor(a){this.#a=athis.a=a}get(){returnthis.#a}}letstudent=newStudent()console.log(Object.getOwnPropertyNames(student))//['a']不能访问属性#a使用#标识私有属性,外部不能直接访问1.4静态方法和静态属性不能实例继承的方法和属性StaticmethodsclassFoo{staticfn1(){this.fn2()}staticfn2(){console.log("Hello");}fn2(){console.log("世界");}}Foo.fn1()//"你好"letfoo=newFoo()foo.fn2()//"World"静态方法可以和实例方法同名,静态方法只能在类上调用classFoo1extendsFoo{}Foo1.fn2()//"你好"子类可以继承父类的静态方法,静态属性和静态方法一样,只需要在实例属性前加上static即可classFoo{static_name="a"_name="b"}console.log(Foo._name);//"a"letfoo=newFoo()console.log(foo._name);//"b"静态方法可以和实例方法同名,实例不能继承静态方法,属于构造函数,不属于原型对象同理,静态方法可以被子类继承1.5new.target属性指向类中的类,继承父类时指向子类类Foo{constructor(){console.log(new.target);}}classFoo1extendsFoo{}letfoo=newFoo()//Fooletfoo1=newFoo1()//Foo1可以用这个方法控制一些类在使用它们之前必须被继承}}}classFoo1extendsFoo{}letfoo=newFoo()//错误需要先继承letfoo1=newFoo1()//Foo12类的继承使用extends关键字复制parent中的属性和方法classtothesubclass2.1super关键字类继承的本质是先创建父类的实例对象this,然后用子类的构造函数对其进行修饰thissuper为子类提供父类的this对象,即相当于Parent.prototype.constructor.call(this),执行父类构造函数并修改thisclassParent{constructor(x,y){this.x=xthis.y=y}getX(){console.log(this.x);}}classChildextendsParent{constructor(x,y,z){super(x,y)this.z=z}getY(){console.log(this.y);}}letobj1=newChild(1,2,3)console.log(obj1);//{x:1,y:2,z:3}obj1.getX()//1obj1.getY()//2super指向父类的原型,可以作为对象调用原型上的方法,修改this指向子类classParent{constructor(x){this.x=xthis.y="a"}getY(){console.log(this.y);}}classChildextendsParent{constructor(x,y){super(x)this.y=y}runner(){super.getY()}}letobj1=newChild(1,2)obj1.runner()//2super.getY()等价于Parent.prototype.getY.call(this)如果Child是on如果没有y属性,父类的y值将返回为“a”。如果Child上有y属性,但是实例化的时候没有传值,会返回undefined,不会走原型链。2.2原型链classA{}classBextendsA{}consta1=newA()constb1=newB()//子类的__proto__指向父类B.__proto__===A//true//父类的原型对象是子类原型对象的原型B.prototype.__proto__===A.prototype//true//父类实例的原型是子类实例的原型b1.__proto__.__proto__===a1.__proto__的关键在于第二个例子。父类的原型对象是子类原型对象的原型。因为类的原型对象是实例对象的__proto__所指向的对象,所以第三个例子2.3Mix-in(敏信)实现可以发起继承多个类,先将多个类混合成一个类,然后继承Minxin的实现//mixinfunctionmix(...mixins){classMix{}for(letmixinofmixins){copyProperties(Max,mixin)copyProperties(Max.prototype,mixin.prototype)}returnMix}//复制属性函数copyProperties(target,source){for(letkeyofReflect.ownKeys(source)){if(key!=="constructor"&&ket!=="prototype"&&key!=="name"){让desc=Object.getOwnPropertyDescriptor(source,key);Object.defineProperty(target,key,desc)}}}ES6标准阮一峰如果只有method来添加,使用Object.assign(target,source)3装饰器(Decorator)装饰器可以用来修改类的行为编译和使用装饰器的写法,转码成向后兼容的ES5写法,这样就可以得到想要的结果这里只是一个类装饰器的例子@addStaticclassA{}functionaddStatic(target){target.hello="Hello"}target为A类,@+装饰功能相当于为A类增加一个静态属性hello属性装饰器,其他内容不再举例
