十一、JS类


一、ES6类

的类并不与其他语言的类完全相同,所具备的独特性正配合了 JS 的动态本质。

二、ES5 中的仿类结构

JS 在 ES5 及更早版本中都不存在类。与类最接近的是:创建一个构造器,然后将方法指派到该构造器的原型上。这种方式通常被称为创建一个自定义类型。

function StudentType(name){
    this.name = name
}

StudentType.prototype.sayName = function(){
    console.log(this.name)
}

let student = new StudentType('张三')
student.sayName()   // 张三

console.log(student instanceof StudentType) // true
console.log(student instanceof Object)      // true

此代码中的 PersonType 是一个构造器函数,并创建了单个属性 name 。 sayName() 方法被指派到原型上,因此在 PersonType 对象的所有实例上都共享了此方法。接下来,使用 new运算符创建了 PersonType 的一个新实例 person ,此对象会被认为是一个通过原型继承了PersonType 与 Object 的实例。
这种基本模式在许多对类进行模拟的 JS 库中都存在,而这也是 ES6 类的出发点。

三、基本的类声明

class StudentClass{
    // 等价于StudentType构造器
    constructor(name){
        this.name = name
    }
    // 等价于StudentType.prototype.sayName
    sayName(){
        console.log(this.name)
    }
}

let student = new StudentClass('kangyun')
student.sayName() // kangyun

console.log(student instanceof StudentClass) // true
console.log(student instanceof Object)  // true

console.log(typeof StudentClass)   // function
console.log(typeof StudentClass.prototype.sayName) // function

自有属性( Own properties ):该属性出现在实例上而不是原型上,只能在类的构造器或方法内部进行创建。在本例中, name 就是一个自有属性。我建议应在构造器函数内创建所有可能出现的自有属性,这样在类中声明变量就会被限制在单一位置(有助于代码检查)

四、类表达式

类与函数有相似之处,即它们都有两种形式:声明与表达式。函数声明与类声明都以适当的关键词为起始(分别是 function 与 class ),随后是标识符(即函数名或类名)。函数具有一种表达式形式,无须在 function 后面使用标识符;类似的,类也有不需要标识符的表达式形式。类表达式被设计用于变量声明,或可作为参数传递给函数。

// 类表达式
let StudentClass = class {
    // 等价于StudentType构造器
    constructor(name){
        this.name = name
    }
    // 等价于StudentType.prototype.sayName
    sayName(){
        console.log(this.name)
    }
}

let student = new StudentClass('kangyun')
student.sayName() // kangyun

console.log(student instanceof StudentClass) // true
console.log(student instanceof Object)  // true

console.log(typeof StudentClass)   // function
console.log(typeof StudentClass.prototype.sayName) // function

五、作为一级公民的类

在编程中,能被当作值来使用的就称为一级公民( first-class citizen ),意味着它能作为参数传给函数、能作为函数返回值、能用来给变量赋值。 JS的函数就是一级公民(它们有时又被称为一级函数),此特性让 JS 独一无二。
ES6 让类同样成为一级公民。这就使得类可以被多种方式所使用。

function createObject(classDef){
    return new classDef()
}

let obj = createObject(class{
        sayHi(){
            console.log('hi')
        }
    }
)

obj.sayHi()

类表达式的另一个用途是立即调用类构造器,以创建单例( Singleton )。为此,你必须使用 new 来配合类表达式,并在表达式后面添加括号。

let person = new class{
    constructor(name){
        this.name = name
    }
    sayName(){
        console.log(this.name)
    }
}('kangyun')

person.sayName()  // kangyun

六、需计算的成员名

对象字面量与类之间的相似点还不仅前面那些。类方法与类访问器属性也都能使用需计算的名称。语法相同于对象字面量中的需计算名称:无须使用标识符,而是用方括号来包裹一个表达。

let methodName = 'sayName'
class StudentClass{
    constructor(name){
        this.name = name
    }
    [methodName](){
        console.log(this.name)
    }
}

let zs = new StudentClass('zs')
zs.sayName()

七、静态成员

ES5 及更早版本中,直接在构造器上添加额外方法来模拟静态成员.

function StudentType(name){
    this.name = name
}
// 静态方法
StudentType.create = function(name){
    return new StudentType(name)
}
// 实例方法
StudentType.prototype.sayName = function(){
    console.log(this.name)
}
var student = StudentType.create('kangyun')

工厂方法 PersonType.create() 会被认定为一个静态方法,它的数据不依赖 PersonType 的任何实例。 ES6 的类简化了静态成员的创建,只要在方法与访问器属性的名称前添加正式的 static 标注。

class StudentClass{
    // 等价于StudentType构造器
    constructor(name){
        this.name = name
    }
    // 等价于StudentType.prototype.sayName
    sayName(){
        console.log(this.name)
    }
    // 等价于StudentType.create
    static create(name){
        return new StudentClass(name)
    }
}

let student = StudentClass.create('kangyun')

静态成员不能用实例来访问,你始终需要直接用类自身来访问它们。

八、使用派生类进行继承

类让继承工作变得更轻易,使用熟悉的 extends 关键字来指定当前类所需要继承的函数,即可。生成的类的原型会被自动调整,而你还能调用 super() 方法来访问基类的构造器。

// 长方形
class Rectangle{
    constructor(length, width){
        this.length = length
        this.width = width
    }
    getArea(){
        return this.length * this.width
    }
}

// 正方形
class Square extends Rectangle{
    constructor(length){
        super(length, length)
    }
}

let square = new Square(3)
console.log(square.getArea())     // 9
console.log(square instanceof Square) // true
console.log(square instanceof Rectangle) // true

此次 Square 类使用了 extends 关键字继承了 Rectangle 。 Square 构造器使用了super() 配合指定参数调用了 Rectangle 的构造器。
继承了其他类的类被称为派生类( derived classes )。如果派生类指定了构造器,就需要使用 super() ,否则会造成错误。若你选择不使用构造器, super() 方法会被自动调用,并会使用创建新实例时提供的所有参数。

在构造器中,你必须在访问 this 之前调用 super() 。由于 super() 负责初始化this ,因此试图先访问 this 自然就会造成错误。
唯一能避免调用 super() 的办法,是从类构造器中返回一个对象。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

永恒的宁静

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值