1. 类的声明
class + 类的名称 {
constructor() {
}
// 方法之间不需要使用逗号隔开,且简写不需要function关键字
functionName1() {}
functionName2() {}
}
- 类声明允许使用
constructor
方法直接定义一个构造器,就不需要先定义一个函数再当做构造器来使用 - 自有属性(实例上的属性)最好都写在构造器函数中,这样有助于代码维护,因为变量都在单一的位置进行声明
// 1.类
class PersonClass {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
let person = new PersonClass("emoji");
person.sayName(); // emoji
console.log(person instanceof PersonClass); // true
console.log(person instanceof Object); // true
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass.prototype.sayName); // "function"
// 2.自定义类型
function PersonType(name){
this.name = name;
}
PersonType.prototype.sayName = function() {
return this.name;
}
let person = new PersonType("emoji");
person.sayName(); // emoji
console.log(person instanceof PersonType); // true
console.log(person instanceof Object); // true
2. 自定义类型和类的区别:
- 类的声明不存在变量提升、会有暂时性死区,就像
let
- 类声明的所有代码都在严格模式下运行
- 类的所有方法都是不可枚举的,自定义类型需要通过
Object.defineProperty()
才能修改为不可枚举
// 类 原型上的方法sayName方法不能被访问到
for(let key in person){
console.log(index);
// name
}
// 自定义类型 原型上的方法sayName方法能被访问到
for(let key in person){
console.log(index);
// name
// sayName
}
- 类的所有方法内部都没有
[[Construct]]
,所以不能用new
来调用?
new.target
属性 检测函数或构造方法是否是通过new
运算符被调用的,在通过new
运算符被初始化的函数或构造方法中,new.target
返回一个指向构造方法或函数的引用。在普通的函数调用中,new.target
的值是undefined
- 调用类构造器时不使用
new
,会报错 - 在类的方法内部重写类名,会报错, 因为在类的内部,类名等同于被
const
声明,不能被重写;反之在外面重写就可以
class Foo(){
constructor(){
// 实例化类名后会报错
Foo = "bar";
}
}
Foo = "baz";
3. 类表达式
类表达式能够被当做值来使用:可以作为参数传给函数、可以作为函数的返回值、可以赋值给变量
- 基本的类表达式主要是代码风格上的差异,就是匿名的方式
let 类名 = class {
// 类内部的代码同类的声明
constructor() {
}
functionName1() {}
functionName2() {}
}
- 具名类表达式,
class
后面跟的类名只能在类的内部被使用
4. 访问器属性
在类的内部,可以在原型上创建一个getter\setter
class CustomHTMLElement {
constructor(element){
this.element = element;
}
get html() {
return this.element.innerHTML;
}
set html(value){
this.element.innerHTML = value;
}
}
var descriptor = Object.getOwnPropertyDescriptor(CustomHTMLElement.prototyp, "html");
console.log("get" in descriptor); // true
console.log("set" in descriptor); // true
console.log(descriptor.enumerable); // false
5. 类的继承
- 使用派生类进行继承 -
extends
- 继承静态成员
- 屏蔽类方法
- 从表达式中派生类
/**
* 人脸识别 FaceDatabase
* @functionName add(name, vector) 支持随时向人脸库中增加特征向量
* @functionName delete(name) 支持随时删除人脸库中的人员
* @functionName update(name, vector) 支持随时更新人脸库中的特征向量
* @functionName search(similarity, vector) 支持从人脸库中搜索所有相似度符合要求的人脸
*/
class FaceDatabase {
constructor() {
// new一个新的map对象
this._map = new Map();
}
/**
* 支持随时向人脸库中增加特征向量
* @param {String} name 特征向量
* @param {Array} vector 库
*/
add(name, vector) {
this.update(name, vector);
}
/**
* 支持随时删除人脸库中的人员
* @param {String} name 特征向量
*/
delete(name) {
this._map.delete(name);
}
/**
* 支持随时更新人脸库中的特征向量
* @param {String} name 特征向量
* @param {Array} vector 库
*/
update(name, vector) {
this._map.set(name, vector);
}
/**
* 支持从人脸库中搜索所有相似度符合要求的人脸
* @param {Number} similarity 相似度
* @param {Array} vector 库
* @return {Array} 人员名称的数组
*/
search(similarity, vector) {
const names = [];
this._map.map((vec, name) => {
if (this.getSimilarity(vector, vec) >= similarity) {
names.push(name);
}
});
return names;
}
/**
* 获取相似度
* @param {Array} vector1 库1
* @param {Array} vector2 库2
*/
getSimilarity(vector1, vector2) {
let similarity = vector1.reduce((sum, item, index) => {
return sum + Math.pow(item - vector2[index], 2);
}, 0);
similarity = Math.sqrt(similarity);
return Math.max(0, 100 - similarity);
}
}