持续创作,加速成长!这是我参与「掘金日新计划 · 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