JS 类总结
创始人
2024-04-10 15:43:53
0

class 关键字是 ES6 新增的。类(class)是ECMAScript 中新的基础性语法糖,本质上还是一个函数,但实际上它使用的仍然是原型和构造函数的概念。并且类受块级作用域限制。

class Person { }
console.log(Person);// class Person { }

定义类

类定义中的代码默认都在严格模式下执行。类包含如下可选内容:

  • 构造函数方法
  • 实例方法
  • 获取函数
  • 设置函数
  • 静态类方法。

空的类定义照样有效。

  • 类声明
    类定义没有像函数那样的声明提升。
class Person {} 
  • 类表达式
    类表达式不能在它们被求值前使用。
const Animal = class {}; 

类的组成

构造函数

在使用 new 操作符创建类的新实例时,会调用 constructor 方法,主要作用是初始化数据。不是必需的,不定义构造函数相当于将构造函数定义为空函数。

使用 new 调用类的构造函数会执行如下操作。

  1. 在内存中创建一个新对象。
  2. 这个新对象内部的 [[Prototype]] 指针被赋值为构造函数的 prototype 属性。
  3. 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)。
  4. 执行构造函数内部的代码(给新对象添加属性)。
  5. 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。
class Animal { }
class Person {constructor(name) {this.name = name;}
}
let animal = new Animal();
let person = new Person('孤城浪人');
console.log(animal); //Animal {}
console.log(person); //Person {name: '孤城浪人'}

默认情况下,constructor 会在执行之后返回当前实例对象。如果 constructor 显示的 return 了一个对象,那么这个对象不会通过 instanceof 操作符检测出跟类有关联,因为这个对象的原型指针并没有被修改。

class Person {constructor(name) {this.foo = name;if (name) {return {name: 'XXXXX'};}}
}
let p1 = new Person(),p2 = new Person('孤城浪人');
console.log(p1); // Person {foo: undefined}
console.log(p1 instanceof Person); // true 
console.log(p2); // {name: 'XXXXX'}
console.log(p2 instanceof Person); // false

我们可以调用实例的 constructor 方法,因为他就是普通函数,只是必须使用 new 关键字调用罢了。

class Person {constructor(name) {this.foo = name;}
}
let p1 = new Person('孤城浪人'),p2 = new p1.constructor('XXXXX');
console.log(p1); // Person {foo: undefined}
console.log(p2); // Person {name: 'XXXXX'}

类可以立即调用

const person = new class Person {constructor(name) {this.name = name;}
}('孤城浪人')
console.log(person);// Person {name: '孤城浪人'}

成员

每次通过 new 调用类标识符时,都会执行类构造函数,这也就意味着在 constructor 中定义的成员每个实例都是一份新的,不会共享。但是不是在 constructor 中定义的成员(不能是原始值或对象)是定义在类的原型上,所有类的实例共享。

const person = class Person {constructor(name) {// 不共享this.name = name;}// 定义在类原型上共享sayName() {console.log(this.name);}
}

类定义也支持获取和设置访问器,方法名支持字符串、符号或计算的值。

class Person {set name(newName) {this.name_ = newName;}get name() {return this.name_;}['sa' + 'y']() {console.log('xxxx');}
}
new Person().say();

静态方法

类可以定义静态方法。它的调用不依赖于实例,静态方法的方法名不能重复

class Person {static sayHellow() {console.log('Hellow');}static say() {console.log('xxxx');}
}
Person.say();//Hellow
Person.sayHellow();//xxxx

迭代

类支持在原型和类本身定义生成器方法,因此可以添加一个默认的迭代器,把类实例变成可迭代对象。

class Person {constructor() {this.names = ['孤城浪人', 'xxxx']}// [Symbol.iterator]() {//   return this.names.entries();// }*[Symbol.iterator]() {yield* this.names.entries();}
}
const person = new Person();
for (let item of person) {console.log(item);
}
// [0, '孤城浪人']
// [1, 'xxxx']

继承

这是类最优秀的特性,原生支持继承,但是本质上还是利用了原型链。使用 extends 关键字,就可以继承任何拥有[[Construct]]和原型的对象,前面说过类就是一个语法糖,他本质上是一个函数,所以 extends 不仅可以继承一个类,也可以继承普通的构造函数。并且 this 永远指向当前实例。

function Person() { };
class Father extends Person {say() {console.log(this);}
}
class Son extends Father { }
const son = new Son();
console.log(son instanceof Father);//true
console.log(son instanceof Person);//true
son.say();//Son{}

这个例子可以看到 Father 继承 Person,Son 继承 Father,所以最后 Son 的实例的原型链中有 Father
和 Person 的原对象,因此 instanceof 返回 true。

super

如果子类需要调用父类的构造函数 constructor 初始化数据,那么只能在子类的构造函数中使用 super 关键字,此外在实例方法和静态方法内部也可以使用 super 关键字。(ES6 给类构造函数和静态方法添加了内部特性 [[HomeObject]] 指向定义该方法的对象。 super 始终会定义为 [[HomeObject]] 的原型)

注意:子类若定义了 constructor 则一定要调用 super,并且不要在调用 super 之前引用 this,否则会抛出 ReferenceError,

class Father {constructor(name) {this.name = name;}say() {console.log(this);}
}
class Son extends Father {constructor() {super('孤城浪人');}sayName() {console.log('sayName')super.say();}
}
const son = new Son();
son.sayName();
// sayName
// Son { name: '孤城浪人' }

如果子类没有构造函数,在实例化子类时会自动调用 super(),而且会把所有传给子类的参数作为 super 的参数传入。

class Father {constructor(name) {this.name = name;}say() {console.log(this);}
}
class Son extends Father {}
const son = new Son('孤城浪人');
son.say();
//Son { name: '孤城浪人' }

抽象基类

抽象基类就是可供其他类继承,但本身不会被实例化的类。可以在构造函数中使用 new.target 属性阻止抽象基类实例化,也可以在其中强制子类要定义某个方法。

class Father {constructor(name) {if (new.target == Father) {throw new Error('不能实例化');}if (!this.say) {throw new Error('缺少say方法');}}
}
class Son extends Father {constructor(name) {super();this.name = name;}say() {console.log(this.name);}
}
const son = new Son('孤城浪人');
son.say();//孤城浪人
new Father()

在这里插入图片描述

我是孤城浪人,一名正在前端路上摸爬滚打的菜鸟,欢迎你的关注。

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...