概述
class (类)作为对象的模板被引入,可以通过 class 关键字定义类。类简要说明
类的本质是function,是基本原型继承的语法糖。所以,JS中继承的模型是不会被改变的。
类既然是函数,那与函数有何不同呢?我们为什么要使用类呢?
有时间,先看一下MDN od
- 函数声明可以被提升,而类声明与let/const 声明类似,不能被提升,也就是在真正执行声明之前,它们会一直存在于临时死区中。
- 类声明中的所有代码将自动运行在严格模式下,而且无法强行让代码脱离严格模式。
- 类中的所有方法,都是不可枚举的。而普通自定义类型中,必须通过Object.defineProperty()方法来指定某方法不可枚举。
- 每个类都有一个[[Construct]]的内部方法,通过关键字new调用那些不含[[Construct]]的方法会导致程序抛出错误。
- 使用除关键字new之外的方式调用构造函数会导致程序抛出错误。
- 在类中修改类名会导致程序报错。
类声明
首先class关键字,然后是类的名字,其它部分的语法,类似于对象字面量方法的简写形式,但不需要在各元素之间使用逗号分隔。
class HelloClass {
constructor(greeting) {
this.greeting = greeting;
}
sayGreeting(){
console.log(this.greeting);
}
}
let hello = new HelloClass('Hello');
hello.sayGreeting(); // Hello
console.log(hello instanceof HelloClass); // true
console.log(hello instanceof Object); // true
console.log(typeof HelloClass); // function
console.log(typeof HelloClass.prototype.sayGreeting); // function
分析:
- constructor为保留方法名,是用来构建对象的,不可用作其它用途。
- 函数定义之前,不需要添加function关键字。
类的属性不可被赋予新值,HelloClass.prototype是一个只可读类属性。
与之等价的ES5声明let HelloClass = (function(){ "use strict"; const HelloClass = function(greeting) { if (typeof new.target === 'undefined') { throw new Error("必须通过关键字new调用构造函数"); } this.greeting = greeting; Object.defineProperty(HelloClass.prototype, "sayGreeting", { value: function() { if (typeof new.target !== 'undefined') { throw new Error("不可使用关键字new调用构造函数"); } console.log(this.greeting); }, enumerable: false, writable: true, configurable: true }); } return HelloClass; }()); let hello = new HelloClass('Hello'); hello.sayGreeting(); console.log(hello instanceof HelloClass); console.log(hello instanceof Object); console.log(typeof HelloClass); console.log(typeof HelloClass.prototype.sayGreeting);
类表达式
类表达式可以是被命名的或匿名的。赋予一个命名类表达式的名称是类的主体的本地名称。和function的表达式类似,但不会像函数声名或和函数表达式一样被提升。
/* 匿名类 */ let Rectangle = class { constructor(height, width) { this.height = height; this.width = width; } }; console.log(typeof Rectangle); // function
/* 命名的类 */ let Rectangle = class Rectangle1 { constructor(height, width) { this.height = height; this.width = width; } }; console.log(typeof Rectange); // function console.log(typeof Rectange1); // undefined
在JS中,函数为一等“公民”,可以传入函数,也可以从函数中返回,还可以赋值给变量的值。类也是JS中的一等公民。
访问器
- getter
- setter
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
可计算成员
const methodName = "sayGreeting";
class HelloClass {
constructor(greeting) {
this.greeting = greeting;
}
[methodName]() {
console.log(this.greeting);
}
}
let hello = new HelloClass('Hello');
hello.sayGreeting(); // Hello
hello[methodName](); // Hello
可计算访问器属性。
const propertyName = "greeting";
class HelloClass {
constructor() {
}
get [propertyName]() {
return this.greetingStr;
}
set [propertyName](value) {
this.greetingStr = value;
}
}
let hello = new HelloClass();
hello.greeting = 'Hello';
console.log(hello.greeting);
生成器方法
class NormClass {
*createIterator() {
yield 1;
yield 2;
yield 3;
}
}
let instance = new NormClass();
let iterator = instance.createIterator();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
为类定义默认迭代器。
class Collection {
constructor() {
this.items = [];
}
*[Symbol.iterator]() {
yield *this.items.values();
}
}
var coll = new Collection();
coll.items.push(1);
coll.items.push(2);
coll.items.push(3);
for (let i of coll) {
console.log(i);
}
// 1
// 2
// 3
静态成员
class Animal {
speak() {
return this;
}
static eat() {
return this;
}
}
let obj = new Animal();
console.log(obj.speak()); // Animal {}
let speak = obj.speak;
console.log(speak()); // undefined
console.log(Animal.eat()); // class Animal
let eat = Animal.eat;
console.log(eat()); // undefined
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。