面向对象新增
Class
- 使用命令方式类似于
let声明的变量一样,不存在变量提升 - 与函数一样,可以使用表达式的形式定义
- 其实应该算 es 5 构造函数的一个语法糖,他本身就是一个函数
new A(); //不存在变量提升,ReferenceError: A is not defined
class A{ //命令方式
}
console.log(typeof A); //function
console.log(A === A.prototype.constructor); //true ,类就指向构造函数
console.log(A.name); //A
var A = class{ //表达式方式
}
console.log(A.name); //A
var B = A; //与A指向同一块内存空间
console.log(B.name); //A 返回函数第一次的变量名
var Outer = class Inner{ //表达式和命令方式同时使用
}
console.log(Outer.name); //Inner
Outer.name = "newName"; //只读属性无法修改默默失效
console.log(Outer.name); //Inner
console.log(Inner.name); //于函数一样只能在内部使用,ReferenceError: Inner is not defined
- 类中的方法必须使用像对象的简写属性那样,但是不能加逗号分隔,同时也可以使用属性表达式的方式定义方法名
- 类中的方法该类定义在原型上,所以为整个类扩展就可以在类的原型上扩展
- 唯一不同的是,在类中直接定义的方法是不可枚举的,而为类扩展的是可枚举的
class A{
fun1(){}
["fun"+2](){}
}
console.log(new A().fun1 === A.prototype.fun1); //true
A.prototype.fun3 = function(){};
console.log(Object.keys(A.prototype)); //[ 'fun3' ]
console.log(Object.getOwnPropertyNames(A.prototype)); //[ 'constructor', 'fun1', 'fun2', 'fun3' ]
- 使用
class关键字定义的类,不能像构造函数那样不使用new关键字也可以调用,不使用new关键字会报错 - 类内部使用的是严格模式,将方法拿出来后,方法中的
this指向会是undefined
class A{
fun(){console.log(this)}
}
console.log(new A());
console.log(A()); //TypeError
let a = new A();
a.fun(); //A {}
let fun = a.fun;
fun(); //undefined
- 同样可以指定某个属性的存取器,在类上定义的存储器属于实例对象而不是属于原型对象上的,只设置 get 未设置 set 则该属性只读
class A {
get p() {
console.log("get");
return this.value;
}
set p(value) {
console.log("set");
this.value = value;
}
fun(){}
}
let a = new A();
a.p = 123; //set
console.log(a.p); //get
//123
console.log(a.p === A.prototype.p); //false
console.log(a.fun === A.prototype.fun); //true
Constructor 方法
- 每个类都要有一个
constructor方法,若没有显式的给定就会默认创建一空的constructor方法 - 该方法中的内容与 es 5 中的构造函数完全一致,使用
new关键字时会调用该方法,this指向创建的对象所以定义在构造方法中的属性属于对象而不是原型对象中 - 若
return一个非对象内容会忽略,若return一个对象则new的时候就是该返回对象而不是this
Static 静态方法
- 使用
static修饰符修饰的方法 - 只能通过类名直接调用,不能通过类的实例对象调用
- 静态方法中的
this指向的是当前类 - 父类的静态方法可以被子类继承
继承
- 子类继承符类使用
extends关键字,并且必须得在子类构造中显式的在this关键字出现之前通过super调用父类构造 - 除拉实例属性和方法以外,父类的静态方法可以被子类继承
class parent { }
class son extends parent {
constructor() {
super();
}
}
//若子类省略构造方法,则会默认创建一个空的且调用父类的方法
class son extends parent {
}
//相当于
class son extends parent {
constructor(...args) {
super(...args);
}
}
Super 关键字
函数形式只能在子类构造方法中使用,其他地方无法使用
| 所处环境 | 使用方式 | 描述 |
|---|---|---|
| 类的构造方法中 | super() 函数方式 |
代表父类的构造方法 |
| 类的方法中 | super.属性 对象方式 |
指向父类的原型对象,并且此时父类中 this 指向子类对象,也就是说不能调用父类实例对象的属性 |
| 对象的方法中 | super.属性 对象方式 |
指向该对象的原型 |
| 类的静态方法中 | super.属性 对象方式 |
指向父类,并且此时父类中 this 指向子类,也就是说子类静态方法中使用该方式调用的是父类静态方法 |
属性的新写法
实例属性
之前版本中,实例属性要通过类中的 constructor 方法添加,现在可以像 Java 那样在构造函数外部直接声明
class A{
constructor(){
this.id = "a";
}
}
console.log(new A().id); //a
//现在的
class A {
id = "a";
age;
}
console.log(new A().id); //a
console.log(new A().age); //undefined
静态属性
之前版本中,静态属性只能在类的外部添加,现在可以像 Java 那样在构造函数外部声明 static 修饰的属性,并且这种方式设置的静态属性会覆盖掉函数原有属性
class A {
}
A.id = "a";
console.log(A.id);
A.name = "a"; //函数name属性是只读的,不会更改
console.log(A.name); //A 返回类名
//现在的
class A {
static id = "a"
static name = "a"; //会覆盖掉函数的name属性
}
console.log(A.id); //a
console.log(A.name); //a 返回设置的,而并非类名
私有属性和方法
之前的版本中类中是没有私有属性和方法的,现在可以使用 # 开头的属性名或方法名定义私有属性和方法了
class A {
#id;
getId(){
return this.#id;
}
setId(id){
this.#id = id;
}
}
const a = new A();
// console.log(a.#id); //SyntaxError 私有属性在类外部使用会报错
a.setId(10);
console.log(a.getId()); //10

Comments NOTHING