11. 新增class
NOxONE 2/21/2022 ES6
# 1. Class
class Person {
constructor(name, id) {
this.name = name
this.id = id
}
toString() {
return `${this.name}: ${this.id}`
}
}
# 1.1 class 特性
- 本质上是一个
函数
- 默认严格模式
- 不存在提升行为
name
属性是 class 关键字后面的类名- 内部
[Symbol.iterator]
表示 Generator 函数
在类中的方法都会定义在prototype
上面
class Person {
constructor(name, id) {
this.name = name
this.id = id
}
toString() {
return `${this.name}: ${this.id}`
}
toValue() {
return this.id
}
}
Object.getOwnPropertyNames(Person.prototype) // ['constructor','toString','toValue']
// 等同于
Person.prototype = {
constructor() {},
toString() {},
toValue() {},
}
Object.defineProperty(Person.prototype, 'constructor', {
value: Person,
writable: false,
enumerable: false, // 不可枚举喔~
configurable: false,
})
类的getter/setter
class Person {
constructor(name, id) {
this.name = name
this.id = id
}
get _id() {
return this.id + 1
}
set _id(value) {
this.id = value
}
}
const p = new Person('jack', 107)
console.log(p._id) // 108
console.log(p.id) // 107
p._id = 100
console.log(p.id) // 100
this 默认指向类实例,但是单独抽离出来会出现错误
class Person {
constructor(name) {
this.name = name
}
sayName() {
this.print(this.name)
}
print(text) {
console.log(text)
}
}
const p = new Person('jack')
p.sayName() // jack
// 抽离出来
const { sayName } = p
sayName() // print is not defined,此时this指向的是window
改进
constructor(name){
this.name = name
this.sayName = this.sayName.bind(this)
}
# 2. Class 静态方法
在一个方法前加上static
关键字时,会定义方法在类上而非原型上,称为静态方法
,即静态方法是供类调用的,非静态方法是供实例调用的
class Foo {
static classMethod() {
return 'hello'
}
}
Foo.classMethod() // 'hello'
var foo = new Foo()
foo.classMethod() // TypeError: foo.classMethod is not a function
在 static 静态方法中,this指向的是类,而非实例
,同时静态方法名可以与非静态方法名重名
class Foo {
static bar() {
this.baz()
}
static baz() {
console.log('class')
}
baz() {
console.log('instance.prototype')
}
}
Foo.bar() // class
super
关键字
- 在
static
方法中指向父类
- 在
非static
方法中指向父类原型
class Foo {
static fn() { // 该方法会定义在类上
return 'static'
}
fn(){ // 该方法会定义在原型上
return 'prototype'
}
fn2:(){ // 该方法会定义实例上
return 'instance'
}
}
class Bar extends Foo {
static fn() {
return super.fn()
}
fn(){
return super.fn()
}
fn2(){
return super.fn2()
}
}
Bar.fn() // "static"
let bar = new Bar()
bar.fn() // "prototype"
bar.fn2() // Uncaught TypeError: (intermediate value).fn1 is not a function
// 这是因为fn2定义在实例上而非原型上,而这里super指向的是父类原型
# 3. Class 实例、原型、静态属性和方法定义
不多 bb 了,直接上代码
class Person{
constructor(key1){
this.key1 = key1 // instance
}
key2 = 1008 // instance
get key3(){ return 'jack' } // prototype (getter/settter)
static key4 = 1007 // constructor
fn1 = function(){} // instance
fn2: function(){} // instance
fn3(){} // prototype
static fn4(){} // constructor
}
# 4. 静态块
ES2022 引入了静态块
,允许在类的内部设置一个代码块,在通过类构造实例运行,用于对静态属性的初始化
class A {
static x
static y
static {
if (+new Date() > 10000) this.x = 1
else this.x = 0 // 将A.x设置为0
}
}
# 5. Class 继承
# 5.1 extends 关键字
在定义子类时,使用extends
关键字指定其父类,在子类内部通过super
指向父类,super()
方法调用父类的constructor
class Father {
constructor(name, id) {
this.name = name
this.id = id
}
fn1() { ... }
static fn2(){ ... }
}
class Son extends Father {
constructor(name, id, age) {
super(name, id) // 调用父类的constructor
this.age = age
}
fn1() {
return super.fn1() + this.age // 调用父类原型的fn1
}
fn2(){
return super.fn2() + this.age // 调用父类的fn2
}
}
注意:子类必须在constructor()
构造方法中调用super()
方法来完成构造,从而获得与父类同样的实例属性和方法,再对其进行扩展,否则报错
若子类没有定义 constructor 方法会默认添加
class Son extends Father {}
//等同于
class Son extends Father {
constructor(...args) {
super(...args)
}
}
由于调用 super 方法,才能通过父类的构造函数创建子类实例,故this
(指向子类实例)要在 super 后才有定义
class Point {
constructor(name, id) {
this.name = name
this.id = id
}
}
class ColorPoint extends Point {
constructor(name, id, color) {
this.color = color // ReferenceError
super(name, id) // 通过父类构造函数创建子类实例
this.color = color // 正确
}
}
# 5.2 super 关键字
在子类构造函数中必须要先调用super()
,这时候会执行父类构造函数,并将 this 执行创建的子类实例
class A {
constructor() {
console.log(new.target.name)
}
}
class B extends A {
constructor() {
super()
}
}
new A() // A
new B() // B