JS中的 class 基础用法

37 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 26 天,点击查看活动详情

JS中的 class 基础用法

start

  • 最近在学习的过程中,发现 class 一直缠绕着我。
  • 对 class 的了解还是不够熟练,导致阅读代码的时候会卡壳,所以今天开始,再学习一下 class 。

ES5 中的构造函数

先复习一下 ES5 中的构造函数。

function Tomato() {
  console.log('我是番茄')

  this.age = '18'
  this.eat = function() {
    console.log('我会吃饭')
  }
}

Tomato.prototype.say = function() {
  console.log('我会说话')
}

var t1 = new Tomato()
// 我是番茄

t1.say()
// 我会说话

1.class 基础语法

class基础使用

class Tomato {}

1.1 class 定义的类名不能重复;

1.2 和定义function不同,class 后面没有括号;

1.3 class 语法是 ES6 版本提供的;

1.4 class 只是一个语法糖,它能实现的功能,ES5 中大部分都可以实现;

1.5 class 只能通过 new 调用;ES5 的构造函数不用 new 也是可以调用的;

1.5 示例

class Tomato {
  say() {
    console.log('我会说话')
  }
}

Tomato()
// TypeError: Class constructor Tomato cannot be invoked without 'new'

/* 

散发一下思维,如何限制函数只能通过 new 调用

function Vue () {
  if ( &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  // ... 其他代码
}

*/

2.class 中的 constructor

class中使用constructor

class Tomato {
  constructor(x, y) {
    this.x = x
    this.y = y
  }
}

回想一下 ES5 中 constructor 是如何使用的?

function Tomato() {}

Tomato.prototype.say = function() {
  console.log('我会说话')
}

console.log(Tomato.prototype.constructor === Tomato) // true

原型链的图解

image.png

constructor 其实就是指向的函数自身,所以下面的写法效果相同。

class Tomato {
  constructor(x, y) {
    this.x = x
    this.y = y
  }
}

function Tomato(x, y) {
  this.x = x
  this.y = y
}

2.1 class中的constructor,简单理解,对应 ES5 中的构造函数。

2.2 class本身是不带括号的,无法接收参数,而constructor可以接收参数。

2.3 通过 new 命令生成对象实例时,自动调用constructor该方法。

2.4 一个类必须有 constructor方法,如果没有显式定义,一个空的 constructor方法会被默认添加。

3. 构造函数的 prototype 上的属性

回想一下 ES5 中如何给构造函数的 prototype 上添加方法?

function Tomato() {}

Tomato.prototype.say = function() {
  console.log('我会说话')
}

ES6 中的 class 如何操作?

class Tomato {
  say() {
    console.log('我会说话')
  }

  eat() {
    console.log('我会吃饭')
  }
}

var t1 = new Tomato()

t1.say() // 我会说话
t1.eat() // 我会吃饭

3.1 ES5 中是直接在函数的prototype属性上新增方法,ES6 中的 class 中则是直接在 class 中定义。

3.2 类的内部所有定义的方法,都是不可枚举的(non-enumerable)。

class Tomato {
  say() {
    console.log('我会说话')
  }

  eat() {
    console.log('我会吃饭')
  }
}

Object.assign(Tomato.prototype, {
  toString() {},
  toValue() {}
})

console.log(Object.keys(Tomato.prototype))
// [ 'toString', 'toValue' ]

console.log(Object.getOwnPropertyNames(Tomato.prototype))
// [ 'constructor', 'say', 'eat', 'toString', 'toValue' ]

可以看到,class 内部 定义的 方法 不可枚举,但是直接在Tomato.prototype添加的方法是可以枚举的。

3.3 在函数的prototype新增非方法的属性?

/* 1. class提供了在函数原型上定义方法的替代方案 */
Tomato.prototype.say = function() {
  console.log('我会说话')
}
class Tomato {
  say() {
    console.log('我会说话')
  }
}


/* 2. 但是我暂时没发现 函数原型上定义属性的替代方案, *所以如果真有这种需求,考虑依旧使用下方的写法* */
Tomato.prototype.age = '18'

4. 构造函数自身上的方法

构造函数,本身也是一个对象,自身也是可以绑定属性。例如 ES5 中是这样写的:

function Tomato() {}

Tomato.target = '标记'
Tomato.palyGame = function() {
  console.log('打游戏')
}

ES6 中 class 的写法:

class Tomato {
  static target = '标记'

  static playGame() {
    console.log('打游戏')
  }
}

4.1 static英文释义:静态。 简单理解,就是构造函数自身的属性,可以使用 static 来定义。

4.2 如果静态方法包含 this 关键字,这个 this 指的是类,而不是实例

4.3 静态方法可以与非静态方法重名。

class Foo {
  static bar() {
    this.baz()
  }
  static baz() {
    console.log('hello')
  }
  baz() {
    console.log('world')
  }
}

Foo.bar() // hello

这个案例就可以验证 4.2, 4.3

4.4 静态属性会被继承

class Foo {
  static text = '123'
  static baz() {
    console.log('hello')
  }
}

Foo.demo = '测试'

class son extends Foo {}

console.log(son.text) // 测试
console.log(son.demo) // 123
son.baz() // hello

5. 实例上的属性

实例上的属性,可以在constructor中定义,或者在 class 内定义。

function Tomato(x, y) {
  this.x = x
  this.y = y
  this.name = '番茄'
  this.age = '18'
}

class Tomato {
  name = '番茄'

  constructor(x, y) {
    this.x = x
    this.y = y
    this.age = '18'
  }
}

基础用法总结

  1. class 的定义
class Tomato {}
  1. 实例上的属性
class Tomato {
  text: '番茄',
  constructor(x, y) {
    this.x = x
    this.y = y
    this.age = '18'
  }
}
  1. 构造函数 prototype 上的方法
class Tomato {
  say() {
    console.log('我会说话')
  }

  eat() {
    console.log('我会吃饭')
  }
}
  1. 构造函数自身上的属性(静态属性 static)
class Tomato {
  static target = '标记'

  static playGame() {
    console.log('打游戏')
  }
}

思考

  • 看完本文,最少要记住 class 中基础用法。

  • 其次看到这么一句话 class 能实现的功能,ES5 中大部分都可以实现。

那么对比 class 那些操作是 ES5 做不了的呢?

  1. class 类必须 new 调用,不能直接执行。
  2. class 类不存在变量提升
  3. class 类中默认严格模式
  4. class 类中定义的 属性和方法 不能枚举;
  • END