Skip to content

ES6 类的使用 ​

一、class 类的定义 ​

按照前面的构造函数形式创建类,不仅仅和编写普通的函数过于相识,而且代码并不容易理解

  • 在 ES6(ECMAScript2015)新的标准中使用了 class 关键字来直接定义类
  • 但是类本质上依然是构造函数、原型链的语法糖而已

定义方式 ​

方式一: 字面量

javascript
class Person {}

var p1 = new Person()
var p2 = new Person()
console.log(p1, p2)

方式二: 表达式

javascript
var Student = class {}

var s1 = new Student()
var s2 = new Student()
console.log(s1, s2)

类的构造函数 ​

  • 每个类都可以有一个自己的构造函数(方法),这个方法的名称是固定的constructor
  • 当通过new 操作符,操作一个类的时候会调用这个类的构造函数constructor
  • 每个类只能有一个构造函数,如果包含多个构造函数,就会抛出异常

当通过 new 操作类时,就会调用这个constructor函数,并且执行以下操作:

  1. 在内存中创建一个新的空对象
  2. 这个对象内部的[[prototype]]属性会被赋值为该类的 prototype 属性
  3. 构造函数内部的 this,会指向创建出来的对象
  4. 执行构造函数的内部代码(函数体代码)
  5. 如果构造函数没有返回非空对象,则返回创建出来的新对象
javascript
class Person {
	// 构造函数
	constructor(name, age) {
		this.name = name
		this.age = age
	}
}

var p1 = new Person('mocha', 18)
console.log(p1.name, p1.age) // mocha 18

console.log(Person.prototype === p1.__proto__) // true

类的实例方法 ​

本质上是放在类的原型上

javascript
class Person {
	constructor(name, age) {
		this.name = name
		this.age = age
	}

	// 实例方法
	// 本质上是放在Person.prototype
	running() {
		console.log(this.name + ' running~')
	}

	eating() {
		console.log(this.name + ' eating~')
	}
}

var p1 = new Person('mocha', 18)
p1.running() // mocha running
p1.eating() // mocha eating

类的静态方法 ​

静态方法(类方法)通常用于定义最直接使用类来执行的方法,不需要有类的实例,使用static关键字来定义

javascript
class Person {
	static hello() {
		console.log('say hello')
	}
}

Person.hello()

类的访问器方法 ​

补充: 针对对象的访问器——描述符方式

javascript
var obj = {
	_name: '',
}

Object.defineProperty(obj, 'name', {
	configurable: true,
	enumerable: true,
	set: function (value) {
		this._name = value
	},

	get: function () {
		return this._name
	},
})

obj.name = 'mocha'

console.log(obj._name) // mocha

补充: 针对对象的访问器——定义访问器

javascript
var obj = {
	_name: '',
	set name(value) {
		this._name = value
	},
	get name() {
		return this._name
	},
}

obj.name = 'mocha'
console.log(obj._name) // mocha

class 类的访问器

javascript
class Person {
	/* 约定:以_开头的属性和方法,不在外界访问 */
	constructor(name, age) {
		this._name = name
		this.age = age
	}

	set name(value) {
		this._name = value
	}

	get name() {
		return this._name
	}
}

var p1 = new Person('mocha', 18)
p1.name = 'kobe'
console.log(p1.name)

应用场景:

javascript
class Rectangle {
	constructor(x, y, width, height) {
		this.x = x
		this.y = y
		this.width = width
		this.height = height
	}

	get position() {
		return { x: this.x, y: this.y }
	}

	get size() {
		return { width: this.width, height: this.height }
	}
}

var rect = new Rectangle(10, 20, 100, 200)
console.log(rect.position) // {x: 10, y: 20}
console.log(rect.size) // {width: 100, height: 200}

class 类和 function 类区别 ​

class 类

javascript
function Person1(name, age) {
	this.name = name
	this.age = age
}

Person1.prototype.running = function () {}
Person1.prototype.eating = function () {}

var p1 = new Person1('mocha', 18)

console.log(p1.__proto__ === Person1.prototype) // true

console.log(typeof Person1) // function

// 不同点:可以作为普通函数调用
Person1('abc', 100)

function 类

javascript
class Person2 {
	constructor(name, age) {
		this.name = name
		this.age = age
	}

	running() {}

	eating() {}
}

var p2 = new Person2('latte', 20)

console.log(p2.__proto__ === Person2.prototype) // true

console.log(typeof Person2) // function

// 不同点:不能作为普通函数调用
Person2('cba', 100)

二、class 类的继承 ​

在 ES6 中新增了extends关键字,可以直接实现继承

javascript
// 父类
class Person {}

// 子类
class Student extends Person {}

super 关键字

  • 执行 super.method(...)来调用一个父类方法
  • 执行 super(...)来调用 constructor
  • 注意:在子类的构造函数中使用 this 或返回默认对象之前,必须先通过 super 调用父类的构造函数

super 的使用位置

  • 子类构造函数

    javascript
    // 父类
    class Person {
    	constructor(name, age) {
    		this.name = name
    		this.age = age
    	}
    }
    
    // 子类
    class Student extends Person {
    	constructor(name, age, sno, score) {
    		super(name, age)
    		this.sno = sno
    		this.score = score
    	}
    }
  • 实例方法

    javascript
    // 父类
    class Person {
    	running() {
    		console.log('running~')
    	}
    }
    
    // 子类
    class Student extends Person {
    	running() {
    		console.log('let us')
    		super.running()
    	}
    }
  • 静态方法

    javascript
    // 父类
    class Person {
    	static sleep() {
    		console.log('sleep')
    	}
    }
    
    // 子类
    class Student extends Person {
    	static sleep() {
    		console.log('let us')
    		super.sleep()
    	}
    }

继承内置类

javascript
class MCArray extends Array {
	get firstItem() {
		return this[0]
	}

	get lastItem() {
		return this[this.length - 1]
	}
}

var arr = new MCArray(10, 20, 30)

console.log(arr.firstItem) // 10
console.log(arr.lastItem) // 10

三、class 类的混入 ​

JavaScript 只支持单继承,不支持多继承

javascript
function mixinAnimal(BaseClass) {
	return class extends BaseClass {
		running() {
			console.log('running~')
		}
	}
}

function mixinRunner(BaseClass) {
	return class extends BaseClass {
		flying() {
			console.log('flying~')
		}
	}
}

class Bird {
	eating() {
		console.log('eating~')
	}
}

var NewBird = mixinRunner(mixinAnimal(Bird))
var bird = new NewBird()
bird.running() // running~
bird.flying() // flying~
bird.eating() // eating~

四、JavaScript 的多态 ​

维基百科的定义: 指为不同数据类型的实体提供统一的接口,或使用一个单一的符号来表示多个不同的类型。

我的总结: 不同的数据类型进行同一个操作,表现出不同的行为就是多态的体现。

Java 中面向对象的多态:

在严格意义的面向对象语言中,多态是存在如下条件的:

  1. 必须有继承(或者是实现接口)
  2. 必须有父类引用指向子类对象
javascript
// 父类
class Shape {
	getArea() {}
}

// 子类
class Rectangle extends Shape {
	constructor(width, height) {
		super()
		this.width = width
		this.height = height
	}

	getArea() {
		return this.width * this.height
	}
}

// 子类
class Circle extends Shape {
	constructor(radius) {
		super()
		this.radius = radius
	}

	getArea() {
		return this.radius ** 2 * 3.14
	}
}

var rect1 = new Rectangle(100, 200)
var rect2 = new Rectangle(20, 30)

var c1 = new Circle(10)
var c2 = new Circle(15)

// 多态的表现形式
function getShapeArea(shape) {
	const area = shape.getArea()
	console.log(area)
}

getShapeArea(rect1) // 20000
getShapeArea(rect2) // 600

getShapeArea(c1) // 314
getShapeArea(c2) // 706.5

JavaScript 中面向对象的多态:

javascript
// 多态的表现

// 为不同数据类型的实体提供统一的接口
function sum(a1, a1) {
	return a1 + a2
}

sum(20, 30)
sum('abc', 'cba')

// 使用一个单一的符号来表示多个不同的类型
var foo = 123
foo = 'hello world'
foo = {}
foo = []

五、对象字面量的增强 ​

ES6 中对 对象字面量 进行了增强,称之为 Enhanced object literals(增强对象字面量)

主要包括:

  1. 属性的简写

    javascript
    var name = 'mocha'
    var age = 18
    
    var obj = {
    	name,
    	age,
    }
    
    console.log(obj.name) // mocha
    console.log(obj.age) // 18
    
    // 函数中的表现
    function foo() {
    	var message = 'hello world'
    	var info = 'my name is mocha'
    
    	return {
    		message,
    		info,
    	}
    }
    
    var result = foo()
    console.log(result.message) // hello world
    console.log(result.info) // my name is mocha
  2. 方法的简写

    javascript
    var name = 'mocha'
    var age = 18
    
    var obj = {
    	name,
    	age,
    	running() {
    		console.log(this.name + ' running~')
    	},
    }
    
    obj.running() // mocha running~
  3. 计算属性名

    javascript
    var key = 'address'
    
    var obj = {
    	[key]: '广州',
    }
    
    console.log(obj.address) // 广州

六、解构 Destructuring ​

ES6 中 新增了一个从数组或对象中方便获取数据的方法,称之为解构。

解构赋值是一种特殊的语法,它使我们可以将数组或对象”拆包“至一系列变量中。

可以划分为:

  1. 数组解构

    javascript
    var names = ['abc', 'cba', 'nba', 'mba']
    
    // 基本使用
    var [name1, name2, name3] = names
    console.log(name1, name2, name3) // abc cba nba
    
    // 有严格的顺序
    var [n1, , n3] = names
    console.log(n1, n3) // abc nba
    
    // 解构出数组
    var [nn1, nn2, ...newNames] = names
    console.log(nn1, nn2, newNames) // abc cba (2) ['nba', 'mba']
    
    // 解构的默认值
    var [nnn1, nnn2, nnn3, nnn4, nnn5 = 'aaa'] = names
    console.log(nnn5) // aaa
  2. 对象解构

    javascript
    var obj = {
    	name: 'mocha',
    	age: 18,
    	height: 1.88,
    }
    var { name, age, height } = obj
    console.log(name, age, height) // mocha 18 1.88
    
    // 对变量进行重命名
    var { name: mName } = obj
    console.log(mName) // mocha
    
    // 默认值
    var { adress: mAddress = '广州' } = obj
    console.log(mAddress) // 广州
    
    // 剩余内容
    var { name: newName, ...newObj } = obj
    console.log(newObj) // {age: 18, height: 1.88}