JavaScript 类

类是一个面向对象的编程概念,在 JavaScript 中它类似于函数。类只是添加到 ES6 中的一个特殊函数。但是,它们通过为其分配属性来为您提供更多的功能和灵活性。

class MyClass {
   …
}

构造 函数

表示类的特殊方法。它用于创建和初始化使用类创建的对象。

class MyClass {
    constructor() {
        this.myName = 'Sandy';
    }
}

let myClass = new MyClass();
console.log(myClass.myName);     // Sandy

构造函数还可以具有参数,用于在实例化时表示具有默认值的类。

class MyClass {
    constructor(name) {
        this.myName = name;
    }
}
let myClass = new MyClass('Tanu');
console.log(myClass.myName);     // Tanu

注意:您可以选择不为类声明构造函数。每个类声明都有一个默认构造函数

class MyClass {
    …
}

MyClass 类具有默认构造函数,如下所示。

constructor() {

}

Getter 和 Setter

AKA 访问器方法,用于计算类的属性值。这些方法基本上分别以关键字和为前缀。

class MyClass {
    constructor() {
        this.myName = 'Sandy';
    }
    get name() {
        return this.myName;
    }
    set name(newName) {
        this.myName = newName;
    }
}

let myClass = new MyClass();
console.log(myClass.name);     // Sandy
myClass.name = 'Tanu';
console.log(myClass.name);     // Tanu

你注意到了吗?这些方法可以在不使用括号的情况下调用,就像普通函数调用一样,这是因为在函数名称之前使用了 get 和 set 关键字。

班级吊装

提升是一种 JavaScript 机制,在代码执行之前,变量和函数声明会移动到其作用域的顶部。类声明不像 JavaScript 变量和函数那样被提升。让我们借助下面的示例来理解这一点。

JS中的功能提升:

getMyName();    // Sandy
function getMyName() {
    console.log('Sandy');
} 

如果您已经注意到,该函数在声明之前被调用。这不会因为 JavaScript 提升而给您带来错误。但是,如果您无法对 JavaScript 类做同样的事情。让我们看看下面的例子。

 JS中的班级吊装:

new MyClass();     // ReferenceError
class MyClass { … }

由于 JavaScript 函数被提升,因此即使类在函数中实例化,也不会被提升。

function myFunction() {
    new MyClass();     // ReferenceError
}

myFunction();     // ReferenceError
class MyClass {}
myFunction();     // OK

类表达式

与函数一样,类也可以用作表达式。有两种方法可以定义类:类声明和类表达式。到目前为止,我们学到的是一个类声明,现在让我们来探索一下类表达式。

let myClassLiteral = class MyClass {
    name() {
        return 'Hi, I am a Sandy';
    }
}

let myClassInstance = new myClassLiteral();
console.log(myClassInstance.name());     // Hi, I am a Sandy

但是,如果您尝试创建 myClass 的实例,它将为您提供 ReferenceError。

let myClassInstance = new MyClass();     // ReferenceError: MyClass is not defined

因此,与函数表达式一样,类表达式可以是匿名的。

let myClass = class {
    name() {
        return 'Hi, I am a Sandy';
    }
}

let myClassInstance = new myClass();
console.log(myClassInstance.name());     // Hi, I am a Sandy

注意:类表达式中的类名 (MyClass) 无关紧要,除非您尝试在类中使用它。是的,你没听错,我们可以访问其中的类名。

let myClassLiteral = class MyClass {
    name() {
        return MyClass.name;
    }
}

let myClassInstance = new myClassLiteral();
console.log(myClassInstance.name());     // MyClass

子类(派生类)

一个类可以从其他类派生而来,带有 extends 子句。您需要做的就是从派生类中调用基类的构造函数(超级构造函数)。由于基类的构造函数是作为超级构造函数调用的,因此可以使用 super() 调用它。你做对了,super 代表你的基类,因此你不仅可以使用它来调用它的构造函数,还可以访问类的成员。如果不调用 super(),则无法派生类。是的,你没听错,它会给你一个错误。

class ParentClass {
    constructor(name, surname) {
	this.parentName = name;
	this.surname = surname;
    }

    getParentName() {
	return this.parentName + ' ' + this.surname;
    }
}

class ChildClass extends ParentClass {
    constructor(childName, parentName, surname) {
	super(parentName, surname);
	this.childName = childName;
    }

    getChildName() {
	return this.childName + ' ' + super.getParentName();	// Reference line A
    }
}

// Instantiate ChildClass
let child = new ChildClass('Sandip', 'Subhash', 'Salunke');

// Access properties of child and parent class
console.log(child.childName);	// Sandip
console.log(child.parentName);	// Subhash
console.log(child.surname);	// Salunke

// Call member functions of child and parent class
console.log(child.getChildName());	// Sandip Subhash Salunke
console.log(child.getParentName());	// Subhash SalunkeI

请注意,如何使用 super 在上面的引用行 A 处调用基类成员函数。现在你可能会想,同样的事情也可以通过而不是 来完成。确实,我们也可以这样做,因为子类是从父类派生的,它可以直接访问其父类的函数。等等,但是如果子类具有同名的函数怎么办?这里有一个区别,我们必须使用 static 来调用父类的函数。

class ParentClass {
    constructor(name, surname) {
	this.parentName = name;
	this.surname = surname;
    }

    getParentName() {
	return this.parentName + ' ' + this.surname;
    }
}

class ChildClass extends ParentClass {
    constructor(childName, parentName, surname) {
	super(parentName, surname);
	this.childName = childName;
    }

    getParentName() {
	return 'Sombody Salunke';
    }

    getChildName() {
	return this.childName + ' ' + this.getParentName();	// Reference line A
    }
}

let child = new ChildClass('Sandip', 'Subhash', 'Salunke');
console.log(child.getChildName());	// Sandip Sombody Salunke

注意:引用行 A,调用,这是子类的本地函数。因此返回的子名称为”this.getParentName()child.getParentName()Sandip Sombody Salunke“而不是””。尝试更改并再次执行代码。太好了,看来你现在得到了正确的孩子名字。S<em>andip Subhash Salunke</em>this.getParentName()super.getParentName()

子类的原型是超类,这都是因为我们扩展了基类。原型的目的是通过向对象添加更多内容来扩展对象的行为,并在创建的所有实例中访问它们。

Object.getPrototypeOf(ChildClass) === ParentClass;	// true

有趣的是,这仅适用于子类的近亲父级。如果从派生类派生类,则其原型将是超类,而不是超超类。

class GrandChildClass extends ChildClass {
    // ...
}

Object.getPrototypeOf(GrandChildClass) === ChildClass;		// true
Object.getPrototypeOf(GrandChildClass) === ParentClass;		// false

我们可以扩展 JavaScript 的内置类,但不建议这样做。通常最好创建自己的类来控制其接口。

class Stack extends Array {
    get topElement() {
        return this[this.length - 1];
    }
}

var stack = new Stack();
stack.push('world');
stack.push('hello');
console.log(stack.topElement); 	// hello
console.log(stack.length); 	// 2

Class 是 ECMAScript 标准,在 ES6 中添加。本教程中演示的大多数概念都是 ES6 功能,如 super、constructor、getter 和 setter、计算方法和属性名称等。

如果你觉得文章还不错,请大家 点赞、分享、留言 下,因为这将是我持续输出更多优质文章的最强动力! 

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

人帝

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

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

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

打赏作者

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

抵扣说明:

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

余额充值