JavaScript:类

本文详细介绍了JavaScript中的类,包括类的定义、类构造函数、类的实例化、类的构成、类方法与静态类方法以及类的继承。通过实例解析了类的使用方式和继承机制,帮助读者掌握JavaScript的面向对象编程思想。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

是可以模拟类的行为的 特殊函数

ECMAScript 中没有正式的“类”这个类型,本质上类就是一种特殊的函数,就像函数是一种特殊的对象。

在 ES6 之前,ECMAScript 没有正式的、规范化的实现继承的语法。

ES6 新增类,来规范化 ECMAScript 中关于继承的实现。

类是 ECMAScript 的基础性语法糖,是对使用原型和构造函数实现继承的规范,是对寄生式组合继承的规范。

类表面上看起来可以支持正式的面向对象编程,但实际上使用的仍然是原型和构造函数来模拟类的行为(继承)。


主要参考资料:

  • 《JavaScript 高级程序设计(第4版)》- P249(274/931)

定义类

定义一个类需要使用关键字 class 。

定义类的方式有两种:

  • 类声明

    类声明,即使用关键字 class 定义一个具名的类。

  • 类表达式

    类表达式,即以表达式的形式使用关键字 class 定义一个类,类名是可选的。

类名一般采用首字母大写的形式。

示例:

  • 定义类。
    class TypeA {}  // 类声明
    
    const TypeB = class {}  // 类表达式,不指定类名
    
    const Type = class TypeC {}  // 类表达式,指定类名
    

类构造函数

类构造函数 是归属于类的构造函数。

定义一个类构造函数需要使用关键字 constructor 作为类构造函数的函数名。

与构造函数一样,在类构造函数中,可以使用对象 this 为类的实例对象添加属性。

类构造函数与构造函数的区别:

类构造函数不能被直接调用。

构造函数能被直接调用。

示例:

  • 类构造函数
    class Type {
    	constructor() {
    		this.instAttr = 'instAttr'
    	}  // 类构造函数
    }
    

类的实例化

类的实例化,即使用操作符 new 调用类创建一个实例对象。

类不能被直接调用,只能使用操作符 new 被调用。

使用操作符 new 调用类,会执行如下操作::

  1. 在内存中创建一个新对象。
  2. 新对象的内部特性 [[Prototype]] 被赋值为 的属性 prototype 。
  3. 调用 类构造函数
  4. 类构造函数 的对象 this 被赋值为新对象。
  5. 执行类构造函数的函数体。
  6. 如果类构造函数有非空的返回值,则返回类构造函数的返回值,否则返回类构造函数的对象 this 。

类可以立即实例化。

即在使用类表达式定义类时,直接使用操作符 new 调用类。

示例:

  • 类的实例化

    class Type {
    	constructor() {
    		console.log('instantiate Type')
    		this.instAttr = 'instAttr'
    	}
    }
    
    const type = new Type()  // 类的实例化
    
    console.log('type.instAttr:', type.instAttr)
    const prototype = Object.getPrototypeOf(type)
    console.log('prototype of type === Type.prototype:', prototype === Type.prototype)
    
    // 输出:
    // instantiate Type
    // type.instAttr: instAttr
    // prototype of type === Type.prototype: true
    
  • 类的立即实例化

    const type = new class Type {
    	constructor() {
    		console.log('instantiate Type')
    	}
    }()  // 类的立即实例化
    
    // 输出:
    // instantiate Type
    

类的构成

关于类的内容需要定义在类的块作用域中

在类块中只能定义方法,不能定义非函数属性。

虽然在类块中不能定义非函数属性,但类本质上是一个函数对象,所以可以在类块外直接为类添加非函数属性。

在类块中定义方法的语法:

使用对象字面量的方法简写的形式定义方法。

方法之间不需要使用逗号操作符 , 分隔。

函数名可以像属性名一样,使用字符串、符号、表达式作为键。

在类块中正常定义的方法可以分为三种:

  • 类构造函数
  • 普通函数
  • 访问器函数

    即访问器属性的获取函数和设置函数

示例:

  • 在类块中定义的三种方法。
    class Type {
    	constructor() {
    		console.log('instantiate Type')
    		this._innerAttr = '1948'
    	}  // 类构造函数
    	
    	generalFunc() {
    		console.log('execute general function')
    	}  // 普通函数
    	
    	// 访问器函数
    	get accessorAttr() {
    		console.log('get accessor attribute')
    		return this._innerAttr
    	}  // 获取函数
    	
    	set accessorAttr(val) {
    		this._innerAttr = val + '-set'
    		console.log('set accessor attribute')
    	}  // 设置函数
    }
    
    const type = new Type()
    console.log('type.accessorAttr:', type.accessorAttr)
    type.accessorAttr = '2017'
    console.log('type.accessorAttr:', type.accessorAttr)
    type.generalFunc()
    
    // 输出:
    // instantiate Type
    // get accessor attribute
    // type.accessorAttr: 1948
    // set accessor attribute
    // get accessor attribute
    // type.accessorAttr: 2017-set
    // execute general function
    

类方法与静态类方法

类方法 ,即类的原型的方法。

在类块中正常定义的方法,会被添加到类的原型,作为类的原型的方法。

静态类方法 ,即类自身的方法。

在类块中使用关键字 static 定义的方法,会被添加到类自身,作为类自身的方法。

示例:

  • 为类定义静态类方法。
    class Type {
    	static staticFunc() {
    		console.log('execute static function')
    	}  // 静态类方法
    }
    
    Type.staticFunc()
    
    // 输出:
    // execute static function
    

类的继承

类支持单继承。

一个类继承另一个类需要使用关键字 extends 。

子类使用关键字 extends 继承父后,子类的原型会被赋值为父类,搭建原型链。

其实使用关键字 extends 可以继承任何拥有内部特性 [[Construct]] 和原型的对象,即函数对象(保持向后兼容)。

示例:

  • 一个类继承另一个类。

    class SuperType {}
    
    class SubTypeA extends SuperType {}  // 类型 SubTypeA 继承类型 SuperType
    
    const SubTypeB = class extends SuperType {}  // 在类表达式中使用关键字 extends 
    
    console.log('SubTypeA.prototype:', SubTypeA.prototype)
    console.log('SuperType is prototype of SubTypeA:', SuperType.isPrototypeOf(SubTypeA))
    
    // 输出:
    // SubTypeA.prototype: SuperType {constructor: ƒ}
    // SuperType is prototype of SubTypeA: true
    
  • 一个类继承一个构造函数。

    function SuperType() {}  // 构造函数
    
    class SubType extends SuperTpye {}  // 继承构造函数
    

派生类

派生类 ,即使用关键字 extends 继承某个类的类。

在派生类中调用父类构造函数,为派生类的实例添加父类的实例属性,需要调用关键字 super 。

关键字 super 只能在派生类的类块中定义的方法内使用。

内部特性 [[HomeObject]] :

在类块中的定义的方法,拥有一个内部特性 [[HomeObject]] ,是一个指针,指向定义方法的对象,即类。

关键字 super 引用 [[HomeObject]] 的原型,即类的原型。

关键字 super 引用派生类的原型,即派生类的父类。

关键字 super 可以像函数一样被调用。

在调用关键字 super 时 ,会调用父类构造函数创建一个父类的实例,并将该实例赋值给当前函数的对象 this 。

通过关键字 super 可以调用父类的静态类方法。

不能单独引用 super 。

示例:

  • 在派生类中调用关键字 super ,为派生类的实例添加父类的实例属性。

    class SuperType {
        constructor() {
            console.log('instantiate SuperType')
    	    this.superInstAttr = '2021'
        }
    }
    
    class SubType extends SuperType {
        constructor() {
            super()  // 调用关键字 super ,为派生类的实例添加父类的实例属性。
            console.log('instantiate SubType')
    	    this.subInstAttr = '2035'
        }
    }
    
    const subType = new SubType()
    console.log('subType:', subType)
    console.log('subType.superInstAttr:', subType.superInstAttr)
    console.log('subType.subInstAttr:', subType.subInstAttr)
    
    // 输出:
    // instantiate SuperType
    // instantiate SubType
    // subType: SubTypeA {superInstAttr: '2021', subInstAttr: '2035'}
    // subType.superInstAttr: 2021
    // subType.subInstAttr: 2035
    
  • 在派生类中通过关键字 super 调用父类的静态类方法。

    class SuperType {
        static superStaticFunc() {
            console.log('execute Super static function')
        }
    }
    
    class SubType extends SuperType {
        static subStaticFunc() {
            super.superStaticFunc()  // 通过关键字 super 调用父类的静态类方法
            console.log('execute Sub static function')
        }
    }
    
    SubType.subStaticFunc()
    
    // 输出:
    // execute Super static function
    // execute Sub static function
    

关键字 super 与类构造函数:

  • 如果派生类没有定义类构造函数。

在实例化派生类时会自动调用 super ,并且传入所有传递给派生类的参数。

  • 如果在派生类中显式定义了类构造函数。

则必须在类构造函数中调用 super ,或者返回一个对象。

在类构造函数中,不能在调用关键字 super 之前使用对象 this 。

即在派生类的类构造函数中,想要使用对象 this 就必须在此之前调用关键字 super 。

综合示例:

  • 类的继承,派生类与父类。
    // 父类
    class SuperType {
        constructor() {
            console.log('instantiate SuperType')
    	    this.superInstAttr = '2045'  // 添加父类实例属性
    	    this._superInnerInstAttr = '2049'
        }  // 父类的类构造函数
        
        static superStaticFunc() {
            console.log('execute Super static function')
        }  // 父类的静态类方法
        
        // 父类的类方法
        superProtoFunc() {
            console.log('execute Super prototype function')
        }  // 普通函数
        
        get superAccessorAttr() {
            console.log('get Super accessor attribute')
    	    return this._superInnerInstAttr
        }  // 获取函数
        set superAccessorAttr(val) {
            console.log('set Super accessor attribute')
    	    this._superInnerInstAttr = val + '-set'
        }  // 设置函数
    }
    
    // 派生类
    class Sub extends SuperType {
        constructor() {
            super()  // 调用关键字 super 
            console.log('instantiate Sub')
    	    this.subInstAttr = '2076'
    	    this._subInnerInstAttr = '2091'
        }
        
        static subStaticFunc() {
            super.superStaticFunc()  // 调用父类的静态类方法
            console.log('execute Sub static function')
        }
        
        subProtoFunc() {
            console.log('execute Sub prototype function')
        }
        get subAccessorAttr() {
            console.log('get Sub accessor attribute')
    	    return this._subInnerInstAttr
        }
        set subAccessorAttr(val) {
            console.log('set Sub accessor attribute')
    	    this._subInnerInstAttr = val + '-set'
        }
    }
    
    Sub.subStaticFunc()
    
    console.log('# --- --- ---')
    const sub = new Sub()
    console.log('sub:', sub)
    
    console.log('# --- --- ---')
    console.log('sub.superInstAttr:', sub.superInstAttr)
    console.log('sub.superAccessorAttr:', sub.superAccessorAttr)
    sub.superAccessorAttr = '2108'
    console.log('sub.superAccessorAttr:', sub.superAccessorAttr)
    
    console.log('# --- --- ---')
    console.log('sub.subInstAttr:', sub.subInstAttr)
    console.log('sub.subAccessorAttr:', sub.subAccessorAttr)
    sub.superAccessorAttr = '2108'
    console.log('sub.subAccessorAttr:', sub.subAccessorAttr)
    
    console.log('# --- --- ---')
    sub.superProtoFunc()
    sub.subProtoFunc()
    
    // 输出:
    // execute Super static function
    // execute Sub static function
    // # --- --- ---
    // instantiate SuperType
    // instantiate Sub
    // sub: Sub {superInstAttr: '2045', _superInnerInstAttr: '2049', subInstAttr: '2076', _subInnerInstAttr: '2091'}
    // # --- --- ---
    // sub.superInstAttr: 2045
    // get Super accessor attribute
    // sub.superAccessorAttr: 2049
    // set Super accessor attribute
    // get Super accessor attribute
    // sub.superAccessorAttr: 2108-set
    // # --- --- ---
    // sub.subInstAttr: 2076
    // get Sub accessor attribute
    // sub.subAccessorAttr: 2091
    // set Super accessor attribute
    // get Sub accessor attribute
    // sub.subAccessorAttr: 2091
    // # --- --- ---
    // execute Super prototype function
    // execute Sub prototype function
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值