持续创作,加速成长!这是我参与「掘金日新计划 · 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
原型链的图解
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'
}
}
基础用法总结
- class 的定义
class Tomato {}
- 实例上的属性
class Tomato {
text: '番茄',
constructor(x, y) {
this.x = x
this.y = y
this.age = '18'
}
}
- 构造函数 prototype 上的方法
class Tomato {
say() {
console.log('我会说话')
}
eat() {
console.log('我会吃饭')
}
}
- 构造函数自身上的属性(静态属性 static)
class Tomato {
static target = '标记'
static playGame() {
console.log('打游戏')
}
}
思考
-
看完本文,最少要记住 class 中基础用法。
-
其次看到这么一句话
class 能实现的功能,ES5 中大部分都可以实现。
那么对比 class 那些操作是 ES5 做不了的呢?
- class 类必须 new 调用,不能直接执行。
- class 类不存在变量提升
- class 类中默认严格模式
- class 类中定义的 属性和方法 不能枚举;
- END