语法
class User{gender = '男';//实例的属性设置的新方法,因为与方法在同一级,因此不需要thisconstructor(name){//小括号用来定义传入参数this.name = name;//设置实例的属性}get(){console.log(this.name)}//不需要function关键字,不需要逗号或者分号,方法可以调用传入的参数changeGender(value){//当然可以通过方法来通过传入参数改变静态属性this.gender = value;}}let user1 = new User();
语法理解:
- 属性名可以用表达式求得
- 类的方法都定义在类的prototype中,这与之前的构造函数是相同的
- 类的内部的所有定义的方法都是不可枚举的(non-enumerable),因为他的descriptor设置了enumerable:false,使用Object.keys()或者for…in循环无法遍历,与构造函数不同。使用in关键字是可以检测的。也可以通过Object.getOwnPropertyNames()方法来查看。obj.hasOwnProperty()的返回值为true。
- 类的constructor方法为默认方法,必须通过new命令生成对象,new命令会默认调用constructor方法、
- 与 ES5 一样,实例的属性除非显式定义在其本身(即定义在this对象上,可以用Object.keys()遍历),否则都是定义在原型上(即定义在class上),所有实例共享一个原型,因此可以通过Object.getPrototypeof()来得到原型,再添加属性、方法,不推荐使用proto。注意,使用实例的proto来修改属性和方法会影响类的prototype,因此会影响类的所有实例,一定要谨慎!!
- class内部默认使用严格模式,因此全局环境下的this指向的undefined。
class表达式
与函数一样,class也可以用表达式定义 ```javascript const MyClass = class Me { getClassName() { return Me.name; } }; let inst = new MyClass(); inst.getClassName() // Me Me.name // ReferenceError: Me is not defined
注意 ,Me是类的名字,但是只能在class的内部可以使用,在外部只能用MyClass来引用,内部不需要用到me时可以省略。<a name="kk0HA"></a># getter和setter关于描述符的介绍,查看[https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty#%E6%8F%8F%E8%BF%B0](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty#%E6%8F%8F%E8%BF%B0)1. 在类中可以使用get.set关键字对某个属性设置getter、setter函数,类比于DOM操作,相当于是监听了该属性的访问、set事件。1. get.set设置的属性在类的prototype上1. get.set的取值函数和存值函数在属性的描述对象上,可以用Object.getOwnPropertyDescriptor( obj,'属性名')取得。1. 通过类生成实例后,get.set的取值函数和存值函数同样在属性的描述对象上,但是这个属性同时在实例中、实例的原型__proto__(类的原型prototype)中```javascriptclass User {gender = "男";constructor(name) {this.name = name;}get prop() {console.log("正在查询");}set prop(value) {console.log("设置值为" + value);}}let user1 = new User("ming");console.dir("get" in Object.getOwnPropertyDescriptor(user1.__proto__, "prop")//true);console.dir("prop" in user1);//trueconsole.dir("prop" in user1.__proto__);//true
静态属性和方法
1.在函数上设置静态方法时,是把函数当成对象,直接设置属性方法(或者在proto上设置)。
2.在类中,在属性和方法的前面加上static关键字,会将属性和方法转化为静态属性和静态方法,静态属性和方法不能在实例中调用,只能以类似Object.keys()这样类的方法形式调用。
3.父类的静态属性和方法可以被子类继承。
注意:静态属性和方法中的this指向类而不是实例。
保护属性的几种方法
1.一种方法是使用不同的命名来防止外部访问,例如_name=name,这样外部不能使用name来访问,而内部使用_name来编写程序。但是这样是不够安全的。
2.使用Symbol()类型的数据来保护属性。
let protect = Symbol();
class User {
constructor(name, age) {
this[protect] = {};//使用symbol声明一个对象整合属性
this[protect].name = name;
this[protect].age = age;
}
}
class user extends User {}
let user1 = new User("xiaoming", "18");
let user2 = new user("xiaohua ", "19");
console.log(user1);
console.log(user2);
console.log(user1.name)//undefined
3.使用weakmap数据类型来存放受保护属性。
私有属性和方法(private)
只有类的内部可以使用,外部使用会报错。
在属性和方法前加上#,将属性和方法转化成私有属性和方法,只能在类和实例的内部引用,外部不能调用。
类的继承
class A {
constructor() {
console.log(new.target.name);
}
}
class B extends A {
constructor() {
super();
}
}
new A() // A
new B() // B
类的原型
子类的proto指向父类,
子类的prototype的proto指向父类的prototype,表示方法的继承
Object.getPrototypeOf检测继承
class Parent {}
class Child extends Parent {}
console.log(Object.getPrototypeOf(Child) === Parent);//true
getPrototypeOf用来检测原型(proto)
子类的proto指向父类,因此可以检测继承。
super关键字
作为函数
继承的时候必须在子类的constructor(只能是构造函数中,别的地方不行)中使用一次super(),这是代表父级的类的constructor。
注意:子类中的super虽然代表的是父类的constructor,但是返回的是子类的实例。
作为对象
普通方法
作为对象调用时,super指向的时父类的prototype,所以定义在父类的实例的方法或者属性是获取不到的。
lass A {
constructor() {
this.p = 2;
}
}
class B extends A {
get m() {
return super.p;
}
}
let b = new B();
b.m // undefined
注意:虽然super指向的是父级的prototype,但是子类普通方法中的super的this是指向子类的实例。
class A {
constructor() {
this.x = 1;
}
print() {
console.log(this.x);
}
}
class B extends A {
constructor() {
super();
this.x = 2;
}
m() {
super.print();//这里指向A中的print,虽然this看起来是A中的print,但其实指向子类的实例,即2
}
}
let b = new B();
b.m() // 2
静态方法
静态方法中,super指向的是父类本身,而不是父类的prototype
class Parent {
static a() {
console.log("a");
}
b() {
console.log("b");
}
}
class Child extends Parent {
static c() {
super.a();
}
static d() {
super.b();
}
}
let v = new Parent();
Child.c(); //a
Child.d(); //报错
同样:静态方法中的super中的this指向的是子类,而不是父类。
class Parent {
static b = "这是父类的static";
static a() {
console.log(this.b);
}
}
class Child extends Parent {
static b = "这是子类的static";
static a() {
super.a();
}
}
console.log(Child.a());//这是子类的static
