一个菜鸟的攻坚系列--class

307 阅读3分钟

一、构造函数和class

ES6之前,JS生成实例对象通过构造函数

function f(width, height){
    this.width = width;
    this.height = height
}
f.prototype.getArea = function(){
    return this.height*this.width
}
let area = new f(10, 20)
area.getArea() //200


ES6,为了更贴近传统面向对象语言的使用方式,引入了类的概念,也就是class。但是class可以看做是一个语法糖,它的实现依然是基于构造函数方式实现的。
ES6中上面的例子可以改写成

class f {
    constructor(width, height){
        this.width = width;
        this.height = height
    }
    getArea(){
        return this.width*this.height
    }
}
let area = new f(10, 20)
area.getArea()  //200

类可以简单地认为是构造函数的另一种写法,是为了更符合面向对象类型编程的思想和方式。因此类的数据类型就是函数,类指向的就是构造函数。同时,类中定义的方法都定义在类的原型上

f.prototype.constructor === f //true
area.getArea === f.prototype.getArea //true


二、class中的getter和setter

可以通过getter和setter监控属性的存取操作

var middle = 0;
class f{
    constructor(){}
    set width(val){
        console.log('设置width的值=', val)
        middle = val
    }
    get width(){
        console.log('获取width的值')
        return middle
    }
}
let o = new f(middle)
o.width = 10 //设置width的值= 10
o.width //获取width的值  10

三、静态方法

静态方法表示不会被实例对象继承的方法,可以直接通过 className.functionName 调用。
和其它语言一样,静态方法也通过 static 定义。

class Student{
    static setStudent(name, age){
        return  `姓名:${name};年龄:${age}`
    }
    static getStudent(){
        return this.setStudent('小明', 18)
    }
}
Student.getStudent()  //"姓名:小明;年龄:18"
let student = new Student()
student.getStudent()  //Uncaught TypeError: student.getStudent is not a function
从上面的例子可以看到,如果通过实例对象访问类中的静态方法,会报错。通过Student.getStudent() 访问时,方法内的 this 指向的是 Student 类。

四、静态属性

class本身的属性,不定义在this上,不会被实例对象继承。
ES6规定,class内部只有静态方法,没有静态属性。
因此,在ES6中定义静态属性只能在类外通过 className.attrName 定义。

class Student{
    constructor(){
        this.name = '小明'
    }
}
Student.school = '北京大学'
let student = new Student()
console.log(student.name); //小明
console.log(Student.school); //北京大学
console.log(student.school); //undefined

但是目前有关于静态属性相关提案,可以通过static关键字定义静态属性,并且此方法也已经在部分浏览器实现,具体可查看 MDN文档

五、class中的this指向

JS中的this指向问题真是千年狐妖,“魅惑”众生啊。
class中的this默认情况下指向的都是类的实例,但是某些情况下也会生变

class Student{
    constructor(name, age){
        this.name = name;
        this.age = age
    }
    getStudent(){
        console.log(this)
    }
}
let student = new Student('小明','18')
student.getStudent()  //Student {name: "小明", age: "18"}
let printStudent = student.getStudent
printStudent()  //undefined

通过上面的例子可以看到,使用实例对象正常去调用 getStudent() 方法,得到的this指向的就是对象本身。但是如果将 getStudent() 赋值给一个变量,再通过变量调用,this指向的就是当前方法运行所在的环境,因为class运行在严格模式下,所以this指向undefined。
当然,class中的函数单独使用this指向的问题可以通过 bind() 进行手动绑定或者使用箭头函数定义(箭头函数中的this总是指向定义是所在的对象,后续不会改变)。但是在实际使用中还是要避免这种方式使用class中的方法。