[JS]类
类的简介
类是用于创建对象的模板,这与其他面向对象编程语言的概念一样。但是,在 JavaScript 中,类实际上是特殊的函数,就像你能够定义的函数表达式和函数声明一样。
构造函数
构造函数是一种专门用于初始化新对象的函数。使用 new 关键字调用构造函数会自动创建新对象,因此构造函数本身只需要初始化新对象的属性。构造函数的 prototype 将被作为新对象的原型的属性。
function Person(name, age) { this.name = name this.age = age } Person.prototype = { run() { return 'run...' }, eat() { return 'eat...' } } let xiaohong = new Person('小红', 11) let xiaoming = new Person('小明', 10) console.dir(Person) // 输出构造函数 console.dir(xiaohong) // 输出实例化对象
构造函数 Person() 的 prototype 被作为新对象的原型的属性。
this 关键字
在构造器初始化属性时,赋值表达式左侧是 this.name ,this 指向的是实例化对象本身。
function Person(name, age) { this.name = name this.age = age console.dir(this) // 打印this } let xiaohong = new Person('小红', 11) console.log(xiaohong) // 打印实例化对象xiaohong
this 指向的是实例化对象 xiaohong。
class 关键字
自 ES6 起,引入了 class 关键字用于创建类。
class Person { constructor(name, age) { this.name = name this.age = age } run() { return 'run...' } eat() { return 'eat...' } } let xiaohong = new Person('小红', 11) let xiaoming = new Person('小明', 10) console.dir(Person) // 输出构造函数 console.dir(xiaohong) // 输出实例化对象
在类中定义的方法,会自动将方法定义在它的原型中。这与上一小节利用构造函数定义的类没有任何区别。因为 class 关键字并未改 JavaScript 类基于原型的本质,它只是定义类的“语法糖”。
static 关键字
静态属性和静态方法属于类,而不属于任何单个对象。在 JavaScript 中,静态属性和静态方法是在构造函数而非实例对象上定义的,所以静态属性和静态方法也称之为类属性和类方法。
静态方法和属性
普通方法和普通属性属于所有实例对象,所以只能以实例对象来调用。静态方法和静态属性是所有对象共享的,所以只能由构造函数名(或类名)来调用。
function Person(name, age) { this.name = name this.age = age } // 定义静态方法run Person.run = function run() { console.log('run...') } // 定义静态属性type Person.type = '人类' let p = new Person('小明', 12) Person.run() // 调用静态方法run Person.type // 调用静态属性type => '人类'
因为静态属性和静态方法是定义在构造函数之上的,所以 Person 的原型 constructor 属性下有静态方法 run 和静态属性 type,而不是 Person 实例对象上的,该实例对象只有 age 和 name 这两个非共享(独立的)的属性。
下面将利用 class 关键字定义类。在 class 关键字定义的类中,只需要在普通方法和属性前加上 static 关键字。
class Person { static type = '人类' constructor(name, age) { this.name = name this.age = age } run() { console.log('normal run...') } static run() { console.log('static run...') } } let p = new Person('小明', 12) Person.run() // 调用静态方法run Person.type // 调用静态属性type => '人类'
私有属性
类属性在默认情况下是公共的,可以被外部类检测或修改。在ES2020 实验草案中,增加了定义私有类字段的能力,写法是使用一个 # 作为前缀。
class Person { #name get name() { return this.#name } set name(name) { this.#name = name } }
私有属性在 Java 中被体现得尤为突出。通常类的属性会被加上 private 使其私有化。这样做的目的是防止外部访问时,意外地修改属性。并且会有一对对应的 getter 和 setter 来操作私有属性。
子类
在面向对象编程中,类 B 可以继承类 A,类 A 是父类,类 B 是子类。类 B 继承类 A 的方法,类 B 也可以定义自己的方法。
在 ES6 及以后,要继承父类,可以简单地在类声明中加上一个extends子句,甚至对内置的类也可以这样。
class EZArray extends Array { get first() { return this[0] } get last() { return this[this.length - 1] } } let a = new EZArray() a instanceof EZArray // true,a是子类的实例 a instanceof Array // true,a是父类的实例 a.push(1, 2, 3, 4) // 子类继承的父类的方法 a.first() // 子类定义的方法 a[1] // 数组的属性访问表达式仍然有效 Array.isArray(a) // true,子类的实例是数组 EZArray.isArray(a) // true,子类继承了静态方法
案例来源于《JavaScript权威指南》- 第9章 - 216页。
一个类使用 extends 继承父类,那么子类的构造函数必须使用 super() 调用父类构造函数。如果在子类中没有定义构造函数,解释器会自动创建一个。
class NormalMap extends Map {} // 未定义构造函数,解释器自动创建 let normalMap = new NormalMap() class UnnormalMap extends Map { // 定义构造函数,但未调用super() constructor(keyType, valueType) { this.keyType = keyType this.valueType = valueType } } let unnormalMap = new UnnormalMap()
UnnormalMap 子类在构造函数中未调用 super() ,因此抛出 ReferenceError 异常。在调用了 super() 之后,一定要确保它在 this 关键字之前,否则也会抛出异常。
- JS转换时间戳为“刚刚”、“1分钟前”、“2小时前”“1天前”等格式
- 纯js选项卡切换
- HTML带有JS的加载
- 亲测:ThinkPHP 调用微信JS-SDK 开发详解
- 如何抓取Js动态生成数据且以滚动页面方式分页的网页
- Node.js中,获取req请求的原始IP
- js怎样实现继承
- js中闭包的理解一
- js 常用正则表达式
- js中写正则表达式验证
- js javascript js控制分页打印,打印分页
- 将js文件编译成动态链接库(dll)文件
- js检测浏览器cookie是否开启
- JS精确到小数点后N位
- eval 函数使用(js)
- aes加密解密(Js & Java)
- 48 - three.js 笔记 - 从本地存储中保存和加载 json 格式的模型
- Vue.js + Vue Router简单实例
- JS实现最简单的轮播图及其原理
- 详解js实时获取并显示当前时间的方法