class
- ES6的class类,只是一个语法糖,只是看起来更像面向对象编程的语法而已,完全可以看作是构造函数的另一种写法
class Person {
constructor(name) {
this.name = name
}
skill() {
return '我的名字叫:' + this.name
}
}
// 相当于
function Person(name) {
this.name = name
}
Person.prototype.skill = function() {
return '我的名字叫:' + this.name
}
- 类本身就指向构造函数
typeof Person // function
Person === Person.prototype.constructor // true
注意:
- 类内部定义的各方法之间无需用逗号隔开
- 定义在类内部的方法是不可枚举的,通过Object.assign()和ES5中直接向构造函数的原型上添加的方法是可枚举的
Object.keys(Person.prototype) // []
Object.getOwnPropertyNames(Person.prototype) // ["constructor", "skill"]
// 通过Object.assign()添加方法
Object.assign(Person.prototype, {
like() {
return '我喜欢运动'
}
})
Object.keys(Person.prototype) // ["like"]
- 类直接调用报错,普通构造函数直接调用不会报错
Person()
// VM2102:1 Uncaught TypeError: Class constructor Person cannot be invoked without 'new'
Student()
// undefined
- 类内部默认constructor,且constructor默认返回this(实例对象),同样也可返回指定对象
class Teacher {
}
// 等同于
class Teacher {
constructor() {}
}
class Foo {
constructor() {
return Object.create(null)
}
}
new Foo() instanceof Foo // false
// 说明:新生成的对象不在原构造函数的原型链上
- 对某个属性设置,getter 和 setter 存值函数和取值函数,拦截该属性的存取行为
class Point {
constructor() {}
get prop() {
return 'getter'
}
set prop(value) {
console.log('setter: ' + value)
}
}
let point = new Point()
point.prop = 123 // setter: 123
point.prop // "getter"
- 属性表达式
let methodName = 'getArea'
class Square {
constructor(){}
[methodName]() {}
}
let s = new Square()
s.__proto__.hasOwnProperty('getArea') // true
- class表达式
// Point是定义在class内部的,不能直接new
const MyPoint = class Point {
say() {
console.log(111)
}
}
(new MyPoint()).say() // 111
// 可以简写为
const MyPoint = class {
say() {
console.log(111)
}
}
// 进而可以写出立即执行的类
const p = new class {
say() {
console.log(111)
}
}
p.say() // 111
注意点
- class内部默认严格模式
- class不存在变量提升
// 不报错
new Student()
function Student(){}
// Person is not defined
new Person()
class Person{}
- this指向
类中方法中的this默认指向实例。但是如果将方法单独提取出来使用(直接调用),this会指向该方法运行时的所在环境,造成的this指向错误问题
class Foo {
say(name = 'jack') {
this.print(name)
}
print(name) {
console.log(name)
}
}
const foo = new Foo()
// foo.say():实例调用,this指向实例
const {say} = foo
// say():直接调用,类中默认开启严格模式,所以this指向undefined
say() // Cannot read property 'print' of undefined
解决办法
- constructor绑定this,给实例添加属性方法
class Foo {
constructor(){
// bind作用:生成一个新的函数、改变this
this.say = this.say.bind(this)
}
say(name = 'jack') {
this.print(name)
}
print(name) {
console.log(name)
}
}
const f1 = new Foo()
const {say} = f1
say() // jack
- 箭头函数(this取决于上下文)
class Foo { constructor(){ console.log('this', this) this.getThis = () => this } } const f1 = new Foo() f1.getThis() === f1 // true
class Foo { // 定义在*实例*上的方法 say = (name = 'jack') => { this.print(name) } // 定义在*原型*上的方法 print(name) { console.log(name) } } const f1 = new Foo() const {say} = f1 say() // jack
- 属性的新写法
通常实例的属性写在constructor里,新写法可以提取出来去掉this与其他方法平级(prop = 0)
- 静态方法
方法前加static关键字,表示构造函数的方法,只能构造函数调用,实例不能调用
- 静态属性
老写法在构造函数上绑定属性(Foo.prop),不符合相关代码放在一起的代码组织原则且容易忽略。新写法在属性前加static关键字,表示构造函数的属性