Javascript中类的定义
类是⽤于创建对象的模板。他们⽤代码封装数据以处理该数据。 JS中的类建⽴在原型上,但也具有某些语法和语义未与ES5类相似语义共享。
实际上,类是“特殊的”,就像你能够定义的和⼀样,类语法有两个组成部分:和。
定义类的⼀种⽅法是使⽤类声明。要声明⼀个类,你可以使⽤带有class关键字的类名(这⾥是“Rectangle”)。
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
提升
函数声明和类声明之间的⼀个重要区别在于, 函数声明会,类声明不会。你⾸先需要声明你的类,然后再访问它,否则类似以下的代码将抛出:
let p = new Rectangle(); // ReferenceError
class Rectangle {}
类表达式是定义类的另⼀种⽅法。类表达式可以命名或不命名。命名类表达式的名称是该类体的局部名称。(不过,可以通过类的(⽽不是⼀个实例的)  属性来检索它)。
// 未命名/匿名类
let Rectangle = class {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
console.log(Rectangle.name);
// output: "Rectangle"
// 命名类
let Rectangle = class Rectangle2 {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
console.log(Rectangle.name);
// 输出: "Rectangle2"
注意: 类表达式也同样受到部分中提到的类型提升的限制。
⼀个类的类体是⼀对花括号/⼤括号{}中的部分。这是你定义类成员的位置,如⽅法或构造函数。
类声明和类表达式的主体都执⾏在下。⽐如,构造函数,静态⽅法,原型⽅法,getter和setter都在严格模式下执⾏。
⽅法是⼀个特殊的⽅法,这种⽅法⽤于创建和初始化⼀个由class创建的对象。⼀个类只能拥有⼀个名为 “constructor”的特殊⽅法。如果类包含多个constructor的⽅法,则将抛出⼀个。
⼀个构造函数可以使⽤super关键字来调⽤⼀个⽗类的构造函数。
参见。
class Rectangle {
// constructor
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea()
}
// Method
calcArea() {
return this.height * this.width;
}
}
const square = new Rectangle(10, 10);
console.log(square.area);
// 100
关键字⽤来定义⼀个类的⼀个静态⽅法。调⽤静态⽅法不需要该类,但不能通过⼀个类实例调⽤静态⽅法。静态⽅法通常⽤于为⼀个应⽤程序创建⼯具函数。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
static distance(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.hypot(dx, dy);
}
}
const p1 = new Point(5, 5);
const p2 = new Point(10,10);
p1.displayName;
// undefined
p1.distance;
/
/ undefined
console.log(Point.displayName);
// "Point"
console.log(Point.distance(p1, p2));
// 7.0710678118654755
当调⽤静态或原型⽅法时没有指定this 的值,那么⽅法内的this 值将被置为undefined。即使你未设置 "use strict" ,因为class体内部的代码总是在严格模式下执⾏。函数prototype
class Animal {
speak() {
return this;
}
static eat() {
return this;
}
}
let obj = new Animal();
obj.speak(); // Animal {}
let speak = obj.speak;
speak(); // undefined
Animal.eat() // class Animal
let eat = Animal.eat;
eat(); // undefined
如果上述代码通过传统的基于函数的语法来实现,那么依据初始的this 值,在⾮严格模式下⽅法调⽤会发⽣⾃动装箱。若初始值
是undefined,this值会被设为全局对象。
严格模式下不会发⽣⾃动装箱,this 值将保留传⼊状态。
function Animal() { }
Animal.prototype.speak = function() {
return this;
}
Animal.eat = function() {
return this;
}
let obj = new Animal();
let speak = obj.speak;
speak(); // global object
let eat = Animal.eat;
eat(); // global object
实例的属性必须定义在类的⽅法⾥:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
静态的或原型的数据属性必须定义在类定义的外⾯。
Rectangle.staticWidth = 20;
Rectangle.prototype.prototypeWidth = 25;
公共和私有字段声明是JavaScript标准委员会提出的。浏览器中的⽀持是有限的,但是可以通过等系统构建后使⽤此功能。
公有字段声明
使⽤JavaScript字段声明语法,上⾯的⽰例可以写成:
class Rectangle {
height = 0;
width;
constructor(height, width) {
this.height = height;
this.width = width;
}
}
通过预先声明字段,类定义变得更加⾃我记录,并且字段始终存在。
正如上⾯看到的,这个字段可以⽤也可以不⽤默认值来声明。
私有字段声明
使⽤私有字段,可以按以下⽅式细化定义。
class Rectangle {
#height = 0;
#width;
constructor(height, width) {
this.#height = height;
this.#width = width;
}
}
从类外部引⽤私有字段是错误的。它们只能在类⾥⾯中读取或写⼊。通过定义在类外部不可见的内容,可以确保类的⽤户不会依赖于内部,因为内部可能在不同版本之间发⽣变化。
私有字段仅能在字段声明中预先定义。
私有字段不能通过在之后赋值来创建它们,这种⽅式只适⽤普通属性。
更多信息,请看.
关键字在类声明或类表达式中⽤于创建⼀个类作为另⼀个类的⼀个⼦类。
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name) {
super(name); // 调⽤超类构造函数并传⼊name参数
}
speak() {
console.log(`${this.name} barks.`);
}
}
var d = new Dog('Mitzie');
d.speak();// 'Mitzie barks.'
如果⼦类中定义了构造函数,那么它必须先调⽤super()才能使⽤this。
也可以继承传统的基于函数的“类”:
function Animal (name) {
this.name = name;
}
Animal.prototype.speak = function () {
console.log(this.name + ' makes a noise.');
}
class Dog extends Animal {
speak() {
super.speak();
console.log(this.name + ' barks.');
}
}
var d = new Dog('Mitzie');
d.speak();//Mitzie makes a nois
e.  Mitzie barks.
请注意,类不能继承常规对象(不可构造的)。如果要继承常规对象,可以改⽤:
var Animal = {
speak() {
console.log(this.name + ' makes a noise.');
}
};
class Dog {
constructor(name) {
this.name = name;
}
}
Object.setPrototypeOf(Dog.prototype, Animal);// 如果不这样做,在调⽤speak时会返回TypeError
var d = new Dog('Mitzie');
d.speak(); // Mitzie makes a nois
e.
你可能希望在派⽣数组类MyArray中返回对象。这种 species ⽅式允许你覆盖默认的构造函数。
例如,当使⽤像返回默认构造函数的⽅法时,您希望这些⽅法返回⼀个⽗Array对象,⽽不是MyArray对象。符号可以让你这样做:
class MyArray extends Array {
// Overwrite species to the parent Array constructor
static get [Symbol.species]() { return Array; }
}
var a = new MyArray(1,2,3);
var mapped = a.map(x => x * x);
console.log(mapped instanceof MyArray);
// false
console.log(mapped instanceof Array);
// true
关键字⽤于调⽤对象的⽗对象上的函数。
class Cat {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Lion extends Cat {
speak() {
super.speak();
console.log(this.name + ' roars.');
}
}
抽象⼦类或者 mix-ins 是类的模板。⼀个 ECMAScript 类只能有⼀个单超类,所以想要从⼯具类来多重继承的⾏为是不可能的。⼦类继承的只能是⽗类提供的功能性。因此,例如,从⼯具类的多重继承是不可能的。该功能必须由超类提供。
⼀个以超类作为输⼊的函数和⼀个继承该超类的⼦类作为输出可以⽤于在ECMAScript中实现混合:
var calculatorMixin = Base => class extends Base {
calc() { }
};
var randomizerMixin = Base => class extends Base {
randomize() { }
};
使⽤ mix-ins 的类可以像下⾯这样写:
class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。