类(class)
在ES6出现前,生成实例对象的传统方法是通过构造函数。
eg:
function Person(name,age){
this.name = name
this.age = age
}
如果想要挂载函数,则需要使用prototype
eg:
function Person(name,age){
this.name = name
this.age = age
}
Person.prototype.showName = function(){
return `名字为:${this.name}`
}
Person.prototype.showAge = function(){
return `年龄为:${this.age}`
}
let p1 = new Person('Fang',20)
console.log(p1.showAge())//年龄为:20
而ES6提供了更接近传统语言的写法,引入了Class这个概念,作为对象的模板。通过class关键字,可以定义类。
eg:
class Person{
constructor(name,age){
this.name = name
this.age = age
}
}
可以看到class里面有一个constructor方法,这就是构造方法,this指向实例对象。
使用方法:
和ES5一样,直接对类使用new命令
class Person{
constructor(name,age){
this.name = name
this.age = age
}
}
new Person('Fang',20)
//Person {name: "Fang", age: 20}
如果想要挂载函数的话,直接将函数写在类中。
class Person{
constructor(name,age){
this.name = name
this.age = age
}
showName(){
return `名字为:${this.name}`
}
showAge(){
return `年龄为:${this.age}`
}
}
let p1 = new Person('Fang',20)
console.log(p1.showName())//名字为:Fang
可以说,ES6的class就是一个语法糖,他的绝大部分功能和ES5一样。
ES6的类和构造函数的类型都是函数。
class Person{}
typeof Person//"function"
注意:
es6的class没有提升功能,在es5中,用函数模拟可以,因为默认函数提升。
new Person()
class Person{}
//Uncaught SyntaxError: Unexpected end of input
name属性
class Person{}
Person.name//Person
属性表达式
类中的属性名也可以使用表达式
eg:
let firstMethod = newName
class Person{
constructor(){
}
[firstMethod](){
}
}
取值函数(getter)和存值函数(setter)
class Person{
constructor(){
}
get aaa(){
return 'aaa的属性'
}
set aaa(value){
console.log(`设置aaa属性,值为:${value}`)
}
}
let p1 = new Person()
p1.aaa = '123'//设置aaa属性,值为:123
console.log(p1.aaa)//aaa的属性
静态方法
类相当于实例的原型,在类中定义的方法都会被实例继承。如果你想用类去调用类自身的方法,就必须使用静态方法,也就是在类里面要调用的方法前面加一个static。
报错情况
class Person{
constructor(){
}
showName(){
return '这是showName方法'
}
aaa(){
return '不使用静态方法'
}
}
let p1 = new Person()
console.log(Person.aaa())//Uncaught TypeError: Person.aaa is not a function
使用静态方法
class Person{
constructor(){
}
showName(){
return '这是showName方法'
}
static aaa(){
return '使用静态方法'
}
}
let p1 = new Person()
console.log(Person.aaa())//使用静态方法
接下来我们探讨一下static中的this指向。
js在es6中虽然定义了class,但class的本质还是function。class中static声明的变量或者函数,是属于function的属性。
回到原来的问题,static的this指向哪里?
class Person{
static showName(){
console.log(this)//this指向哪里
}
}
等价于
function Person(){
}
Person.fun = function(){
console.log(this)
}
从上面的代码我们可以看出,this指向Person,也就是类本身。
类的继承
es5的继承方式比较复杂:
function Person(){
this.name = name
}
Person.prototype.showName = function(){
return'名字是:${this.name}'
}
//子类
function Student(name,skill){
Person.call(this,name)//继承属性
this.skill = skill
}
Student.prototype = new Person()//继承方法
let stu1 = new Student('小明','逃学')
console.log(stu1.showName)
现在es6提供了继承的关键字:extends
这样相比es5就变得方便多了
class Person{}
class Stduent extends Person{}
es6中规定,子类的构造函数中必须执行一个super函数,也可以理解为父级的功能函数
class Person{
constructor(){
this.name = name
}
}
class Student extends Person{
constructor(){
super(name)
this.skill = skill
}
showSkill(){
return `爷的技能为:${this.skill}`
}
}
如果出现子类的函数名与父类函数名相同的情况下,又想一起执行,可在子类的同名函数里使用super关键字来调用父级函数执行
class Person{
constructor(name){
this.name = name
}
showName(){
console.log('父类showName')
return `父类showName`
}
}
class Student extends Person{
constructor(name,skill){
super(name)
this.skill = skill
}
showName(){
super.showName()
console.log('子类showName')
}
showSkill(){
return `爷的技能为:${this.skill}`
}
}
let p1 = new Student('fang','run')
p1.showName()
//父类showName
//子类showName
es5的继承,原理是先创建子类的实例对象this,然后再将父类的添加到子类的this上面(parent.apply(this))。而es6的继承则是先将父类的属性和实例方法添加到this上面,也就是要先调用super方法的原因,再用子类的constructor来增加this的属性和方法。
父类的静态方法,也会被子类继承
eg:
class Person{
static hello(){
console.log('hello')
}
}
class Student extends Person{}
Student.hello()//hello
Object.getPrototypeOf()
Object.getPrototypeOf()可以用来从子类获取父类
Object.getPrototypeOf(Student) === Person//true
类的prototype和__proto__
Class同时具有prototype和__proto__。
1.子类的__proto__属性表示构造函数的继承,指向父类
2.子类的prototype的__proto__属性表示方法的继承,指向父类的prototype属性
eg:
class Person{}
class Student extends Person{}
Student.__proto__ = Person//true
Student.prototype.__proto__ = Person.prototype//true
这样是因为类的继承时按照以下方式实现的:
class Person {
}
class Student {
}
// Person 的实例继承 Student 的实例
Object.setPrototypeOf(Student.prototype, Person.prototype);
//相当于
Student.prototype.__proto__ = Person.prototype
// Student 继承 Person 的静态属性
Object.setPrototypeOf(Student, Person);
//相当于
Student.__proto__ = Person
如果您觉得我的文章有用,欢迎点赞和关注,也欢迎光临我的个人博客github.com/BokFang