ES6

class使用

1.1 基本使用和写法

  • 写法1: 声明
1
2
3
4
5
6
7
8
9
10
11
12
13
class Obj {
constructor (x, y) {
this.x = x
this.y = y
}
add () {
return this.x + this.y
}
}
let f = new Obj(1, 3)
console.log(f.x, f.y) // 1 3
console.log(f.add()) // 4
console.log(f) // Obj
  • 写法2: 表达式
1
2
3
4
5
6
7
8
const notUseInner = class {
constructor (x, y) {
this.x = x
this.y = y
}
}
let not = new notUseInner(3, 5)
console.log(not.x, not.y) // 3 5
  • 写法3:具名表达式
1
2
3
4
5
6
7
8
9
10
11
const useInner = class Me {
constructor (x, y) {
this.x = x
this.y = y
}
add () {
return Me.name
}
}
let use = new useInner(2, 9)
console.log(use.add()) // Me

1.2注意事项

  • 事项1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Point {
// 如果不是函数,这个data将是对象的属性,不会挂在prototype上,实例属性的新写法,一般写在顶层
data = 3
constructor() {
}

toString() {
}
toValue() {
}
}

// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
  • 事项2
1
2
3
4
5
6
7
8
9
// 属性可以使用表达式
let methodName = 'getArea';

class Square {
constructor(length) {
}
[methodName]() {
}
}
  • 事项3
1
2
3
// 不存在变量提升
new Foo();
class Foo {}
  • 事项4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// class 创建的对象,方法是不可以枚举的
class Obj {
constructor (x, y) {
this.x = x
this.y = y
}
add () {
return this.x + this.y
}
}
let f = new Obj(1, 3)
for (let a in f) {
console.log(a)
}

// es5 构造函数方式则可以
function Dd () {
this.a = 3
this.mes = function () {
return 4
}
}
Dd.prototype.way = function () {
return 5
}
let aa = new Dd()
for (let b in aa) {
console.log(b)
}
  • 事项5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 结构赋值的this指向问题。
class Logger {

// 解决方法2 bind的this
// constructor () {
// this.printName = this.printName.bind(this)
// }

printName(name = 'there') {
this.print(`Hello ${name}`);
}
// 解决方法2: 使用箭头函数
// printName = (name = 'there') => {
// this.print(`Hello ${name}`);
// }

print(text) {
console.log(text);
}
}

const logger = new Logger();
const { printName } = logger;
printName(); // TypeError: Cannot read property 'print' of undefined

1.3 使用set和get

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let a = 3
class TestGetSet {
constructor () {
// this.name
}
get name () {
console.log('访问了name属性')
return a
}
set name (val) {
console.log('赋值了name属性')
a = val
}
}
let result = new TestGetSet()
result.name = 6
console.log(result.name)

1.4 使用静态属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class ObjStatic {
// 静态属性、方法不会被“实例”继承,但可以被子类继承
static names = {
firstName: 'ys'
}
static getName () {
return 'liuys'
}
// 非静态属性、方法可以和静态属性、方法重名
getName () {
return 'not static liuys'
}
}
class SubObjStatic extends ObjStatic {
subPro = {
age: 33
}
}
// 静态属性、方法可以直接访问
console.log(ObjStatic.names)
let newObj = new ObjStatic()
console.log(newObj) // 实例化不会继承static
console.log(SubObjStatic.getName()) // 继承ObjStatic
console.log(SubObjStatic.names) // 继承ObjStatic

1.5 私有方法

1
2
3
4
5
6
7
8
9
10
// 将真正的方法要执行的逻辑放到外面的函数,内部通过call调用
class Widget {
foo (baz) {
bar.call(this, baz);
}
}

function bar(baz) {
return this.snaf = baz;
}

1.6 继承

  • super代表父类构造函数,但是返回的是子类的实例。如A是B的父类,那么super的功能相当于A.prototype.constructor.call(this)

  • ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))

  • ES6 的继承机制完全不同,是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),再用子类的构造函数修改this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

class A {
constructor () {
this.x = 3
this.y = 4
}
}

class B extends A {
// 如果B内设置construstor,必须执行super() ,否则报错
// constructor (m, n) {
// 在super之前会导致报错
// this.m = m
// super()
// this.n = n
// }
getVal () {
return this.x + this.y
}
}
  • 在ES5中,每个实例对应的proto都是指向对应构造函数的prototype方法

class中,存在两条链级关系

  • 子类的proto指向父类

  • 子类prototype属性的proto指向父类的prototype属性

1
2
3
4
5
6
7
8
class A {
}

class B extends A {
}

B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
返回
顶部