本质是构造函数的语法糖 目的是让类的声明与继承更加简洁清晰
声明定义
class
* 使用 new 关键字构造对象实例
* class 定义的方法不能枚举
* class 默认使用严格模式执行
class Human {
constructor(name, age) {
this.name = name;
this.age = age;
};
run() {};
eat() {};
}
var human = new Human("zhangsan", 18);
console.log(Object.keys(human)); // ["name", "age"], 无法遍历方法
构造器
constructor
构造器用于传递对象的初始参数
* 非必须的
* 如果没有显性定义构造函数,系统会自动创建构造函数,并实现继承
* 子构造器必须调用完 super 后才可以使用 this
* 主要目的是纠正 this 指向
class Human {}
/**
* 等效于
* class Human {
* constructor(...args) {
* super(...args);
* }
* }
*/
// 传递初始值
class Male {
constructor(name) {
this.name = name;
}
}
静态属性、方法
静态属性和方法是可以被继承使用的
static
* 静态属性、方法是类自身的属性、方法
* 一般情况下,不需要对象属性参与计算的方法可以定义为静态方法
class Human {
static eat() {
console.log("eat");
}
}
var human = new Human();
Human.eat(); // "eat"
human.eat(); // error: human.eat is not a function
访问器
getter / setter
* 类似对象中的属性访问器
class Human {
_name = "zhangsan";
get name() {
return this._name;
}
set name(name) {
this._name = name;
}
}
var human = new Human();
console.log(human.name); // "zhangsan"
human.name = "lisi";
console.log(human.name); // "lisi"
访问控制
* javascript 中没有访问修饰符
* 通过约定实现访问控制的效果
public
公共的、不受保护的属性。 类的内部、外部、继承的子类都可以访问
class Human {
name = "zhangsan";
}
var human = new Human();
console.log(human.name); // "zhangsan"
protected
受保护的属性 类的内部、继承的子类可以访问,类的外部无法访问
* 约定以 _ 开头的变量或方法为受保护的
* 外部通过访问器 setter 修改受保护的属性或方法
*外部通过访问器 getter 访问受保护的属性或方法**
class Human {
_name;
set name(name) {
this._name = name;
}
get name() {
return this._name;
}
}
通过 Symbol 结合访问器定义内部属性、方法名,实现属性保护
* 无法实现完全的受保护,当通过定义的 Symbol 变量访问时,可以访问到。使用新的 Symbol 变量无法访问
const protects = Symbol();
class Human {
constructor() {
this[protects] = {};
this[protects].name = "zhangsan";
}
set name(name) {
this[protects].name = name;
}
get name() {
return this[protects].name;
}
}
var human = new Human();
console.log(human[protects].name); // "zhangsan"
console.log(human.name); // "zhangsan"
console.log(human[Symbol()].name); // error: Cannot read property "name" of undefined
**
通过 WeakMap 定义内部属性、方法名,实现属性保护
* 可以实现完全的受保护
const protects = new WeakMap();
class Human {
constructor() {
protects.set(this, "zhangsan");
}
set name(name) {
protects.set(this, name);
}
get name() {
return protects.get(this);
}
}
var human = new Human();
console.log(human.name); // "zhangsan"
private
私有属性 只有类的内部可以访问,类的外部、继承的子类无法访问
* 约定以 # 开头的变量或方法为私有的
*外部通过访问器 setter 修改私有的属性或方法
* **外部通过访问器 getter 访问私有的属性或方法
class Human {
#name = "zhangsan";
set name(name) {
this.#name = name;
}
get name() {
return this.#name;
}
}
var human = new Human();
console.log(human.name); // 张三
继承
extends
* 继承必须在子类构造函数中调用 super() 执行父类的构造函数
class Human {}
class Male extends Human {
constructor() {
super();
}
}
super
* 指父类引用
* 只能在类或对象的方法中使用,不能在函数中使用
class Human {
run() {
console.log("run");
}
}
class Male extends Human {
constructor() {
super();
}
eat() {
super.run();
}
}
var male = new Male();
male.eat(); // "run"
多继承
* javascript 不能实现多继承
* 使用多个类的方法,可以通过 mixin 混合模式实现
mixin
* 通过 Object.assgin() 将多个类的原型对象中的方法进行合并
class Tool {
sum(nums) {
return nums.reduce((pre, cur) => pre + cur, 0);
}
}
class Item {
#list = [];
constructor(...list) {
this.#list = list;
}
get list() {
return this.#list;
}
}
// 混合操作
Object.assign(Item.prototype, {
sum: Tool.prototype.sum
});
var item = new Item(1, 2, 3, 4, 5);
var total = item.sum(item.list); // 15