定义
class Person {
constructor() {}
speak() {}
}
表达式
const Person = class {
constructor() {}
speak() {}
};
调用
new Person();
立即执行
new (class {
constructor() {
console.log("cons");
}
})();
// 对比构造函数
(function () {
console.log("func");
})();
类名
首字母大写
构造方法
可不写,浏览器会自动补
实例化时执行构造方法
1)属性/方法定义在构造方法中(实例上)-实例属性/方法,不共享
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
//定义在构造方法中,各实例方法不共享
// 各方法有各自地址,占用更多内存
this.speak = () => {};
}
}
const zs = new Person("ZS", 18);
const ls = new Person("LS", 20);
console.log(zs.speak === ls.speak); //false
2)属性/方法定义在构造方法外(原型上)-用于赋予对象默认属性值;各实例方法共享
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
// 定义在构造方法外,各实例共享
speak() {
console.log("speak");
}
}
const zs = new Person("ZS", 18);
const ls = new Person("LS", 20);
console.log(zs.speak === ls.speak); //true
与构造函数本质相同
Class
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
// 本质:在原型上添加函数
speak() {
console.log("speak");
}
}
构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.speak = function () {
console.log("speak");
};
属性和方法
实例属性&静态属性
静态就是类的
class Person {
// 实例属性1:赋给对象默认的属性值
country = "美国";
constructor(name) {
// 实例属性2
this.name = name;
}
// 静态属性写法1:新提案,注意兼容
static version = "1.0";
// 静态属性写法2:方法的返回值形式
static getVersion() {
return 1.0;
}
}
const p = new Person("Alex");
console.log(p.name); //Alex
console.log(p.country); //美国
console.log(Person.version); //1.0
console.log(Person.getVersion); //ƒ getVersion() { return 1.0;}
实例方法&静态方法
实例方法-实例的方法-通过原型定义-用实例.方法名去调用
静态方法-类的方法-用函数直接定义-用类名.方法名去调用
class Person {
constructor(name) {
this.name = name;
}
// 实例方法写法1
speak() {
console.log("speak");
// this指向实例
console.log(this);
}
// 静态方法写法1
static speak() {
console.log("人类可以说话");
// this指向类
console.log(this);
}
}
// // 实例方法写法2
// Person.prototype.speak = function () {
// console.log("speak");
// // this指向实例
// console.log(this);
// };
// 静态方法写法2-不利于类的封装,不建议
// Person.speak = function () {
// console.log("人类可以说话");
// // this指向类
// console.log(this);
// };
const p = new Person("Alex");
console.log(p.name); //Alex
console.log(p.country); //美国
// 调用实例方法
p.speak();
// 调用静态方法
Person.speak();
私有属性&私有方法
一般情况下,类的属性和方法是公开的;可被外界修改,造成意想不到的错误
class Person {
constructor(name) {
this.name = name;
}
}
const p = new Person("Alex");
console.log(p.name); //Alex
p.name = "ZS";
console.log(p.name); //ZS
ES6原生中无私有属性/方法,需要模拟
方法一:_开头
class Person {
constructor(name) {
this._name = name;
}
// 访问接口
getName() {
return this._name;
}
}
const p = new Person("Alex");
console.log(p.getName()); //Alex
p.name = "ZS";
console.log(p.getName()); //Alex
方法二:利用IIFE特性(可形成单独作用域)
相较于方法一,私有性更强
// 封装
(function () {
// 被移出的类
let username = "";
class Person {
constructor(name) {
username = name;
}
// 访问接口
getName() {
return username;
}
}
//在全局中复制一个Person类
window.Person = Person;
})();
// 调用
(function () {
const p = new Person("Alex");
console.log(p.getName()); //Alex
p.name = "ZS";
console.log(p.getName()); //Alex
})();
继承
extends
继承父类所有方法和属性
同名覆盖原则-改写方法和属性
增加自有方法和属性
class Person {
constructor(name, sex) {
// 实例属性
this.name = name;
this.sex = sex;
// 实例方法-不共享
this.say = function () {
console.log("speak1");
};
}
// 实例方法-共享
speak() {
console.log("speak2");
}
// 静态方法
static speak() {
console.log("static speak");
}
}
// 静态属性
Person.version = "1.0";
class Programmer extends Person {
// 子类增加属性:feature
constructor(name, sex, feature) {
super(name, sex);
// this不可在super之前
this.feature = feature;
}
// 子类方法改写:同名覆盖
speak() {
console.log("speak2new");
}
}
// 子类属性改写:同名覆盖
Programmer.version = "2.0";
super
作为函数
代表父类的构造方法,只能用于子类的构造方法,用于其他地方报错
虽代表父类的构造方法,但内部的this指向子类的实例
class Person {
constructor(name) {
this.name = name;
console.log(this); //Programmer {name: undefined}
}
}
class Programmer extends Person {
constructor(name, sex) {
super(name);
this.sex = sex;
console.log(this);
//Programmer {name: undefined, sex: undefined}
}
hi() {
// super();//报错
}
}
new Programmer();
作为对象-用于构造方法中
代表父类原型对象,Person.prototype;故定义在父类实例上的方法或属性,无法通过super调用
用super调用父类原型上的方法时,方法内部this指向当前的子类实例
class Person {
constructor(name) {
// 定义在父类实例上的属性
this.name = name;
}
// 定义在父类原型上的属性
speak() {
console.log("speak");// speak
console.log(this); //Programmer {name: 'ZS', sex: 'male'}
}
}
class Programmer extends Person {
constructor(name, sex) {
super(name);
this.sex = sex;
// super不可访问定义在父类实例上的属性;
console.log(super.name); //undefined
// super可访问定义在父类原型上的属性
super.speak();
}
}
new Programmer("ZS", "male");
作为对象-用于一般方法中(特点同构造方法)
代表父类原型对象Person.prototype;
故定义在父类实例上的方法或属性,无法通过super调用
用super调用父类原型上的方法时,方法内部this指向当前的子类实例
class Person {
constructor(name) {
this.name = name;
}
speak() {
console.log("speak"); //speak(输出2)
console.log(this);
//Programmer {name: 'ZS', sex: 'male'}(输出3)
}
}
class Programmer extends Person {
constructor(name, sex) {
super(name);
this.sex = sex;
}
speak() {
// super不可访问定义在父类实例上的属性;
console.log(super.name); //undefined(输出1)
// super可访问定义在父类原型上的方法
// 1)先继承父类的speak()内容
super.speak();
// 2)再写子类的speak()内容
console.log("Programmer speak");
//Programmer speak(输出4)
}
}
const p = new Programmer("ZS", "male");
p.speak();
作为对象-用于静态方法中-报错
静态方法里只能调用静态方法、只能使用静态属性
代表父类,而不是父类原型
用super调用父类原型上的方法时,方法内部this指向当前的子类
class Person {
constructor(name) {
this.name = name;
}
static speak() {
console.log("Person speak"); //Person speak
console.log(this); //class Programmer extends Person {...}
}
}
class Programmer extends Person {
constructor(name, sex) {
super(name);
this.sex = sex;
}
static speak() {
super.speak();
console.log("Programmer speak"); //Programmer speak
}
}
Programmer.speak();
显式指定作为函数还是对象,否则报错
class Person {
constructor(name) {
this.name = name;
}
speak() {
console.log("speak");
}
}
class Programmer extends Person {
constructor(name, sex) {
// 显示指定-作为函数用
super(name);
this.sex = sex;
// 不指定报错
// console.log(super);
// 显示指定-作为对象用
console.log(super.speak);
}
}