欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ES6中类的概念

程序员文章站 2022-07-16 22:04:56
...

Class

在JavaScript中,是通过构造函数来生成实例对象。

function A(a){
    this.a=a
}
A.prototype.sayA=function(){
    console.log(this.a)
}
var a=new A('a')
a.sayA()

在ES6中引入了class(类)的概念,通过class关键字可以定义类。这种写法使得对象原型的写法更加清晰、更像面对对象编程的语法了。

class A{
    constructor(a){
        this.a=a
    }
    sayA(){
        console.log(this.a)
    }
}
var a=new A('a')
a.sayA()

在定义类的方法时,不需要加上function关键字,使用的时候也是直接对类进行new命令,跟构造函数是一样的。

构造函数的prototype属性,在 ES6 的类中继续存在,类的所有方法都定义在类的prototype属性上面。

class A{
    constructor(){
    }
    sayA(){}
    sayB(){}
}

相当于

A.prototype={
	sayA(){},
	sayB(){}
}

因此在类的实例中调用方法,其实调用的是原型上的方法。而且,类的内部定义的所有方法都是不可枚举的,而es5中的是可枚举的。

class A{
    constructor(){
    }
    sayA(){}
    sayB(){}
}
Object.keys(A.prototype) //[]

function A(){}
A.prototype.sayA=function(){}
A.prototype.sayB=function(){}
Object.keys(A.prototype) //['sayA','sayB]

constructor

constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。

class A(){}
//等同
class A(){
	constructor(){}
}

类的实例

实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。

class A{
    constructor(a){
        this.a=a
    }
    sayA(){
        console.log(this.a)
    }
}
var a=new A('a')
console.log(a.hasOwnProperty('a'))    //true
console.log(a.hasOwnProperty('sayA'))  //false
console.log(a.__proto__.hasOwnProperty('sayA'))  //true

类的所有实例共享一个原型对象。

var a=new A('a')
var b=new A('b')
console.log(a.__proto__===b.__proto__)   //true

可以通过__proto__属性对类添加方法。

getter、setter

在类的内部可以使用getset关键字,对某个属性设置存取函数,拦截属性的存取行为。

class A{
    constructor(a){
        this.a=a
    }
    get value(){
        return this.a
    }
    set value(val){
        this.a=val
    }
}
var a=new A()
a.value=3
console.log(a.value)  //3

属性表达式

类的属性名,可以通过表达式设置

let methodsName1='sayA'
class A{
    constructor(){}
	[methodsName1](){}
}

class表达式

与函数一样,类也可以用表达式的形式进行定义。

const Aclass= class A{
	sayA(){
		return A.value
	}
}

这个类的名字是AA只在 Class 的内部可用,指代当前类。在 Class 外部,这个类只能用AClass引用。如果类的内部没有用到的话,可以直接写成

const Aclass=class{}

采用class表达式的写法,可以写出立即执行的class

const Aclass=new class A{
    constructor(value){
        this.value=value
    }
	sayA(){
		console.log(this.value)
	}
}('a')
Aclass.sayA()   //a

静态方法

在方法前面加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

class A{
	static aMethod(){
		console.log('hi')
	}
}
A.aMethod()   //hi
var a=new A() 
a.aMethod()   //TypeError: a.aMethod is not a function

如果静态方法包含this关键字,这个this指的是类,而不是实例。静态方法可以与非静态方法重名

class A{
	static aMethod1(){
		this.aMethod2()   //this指向了类A,而不是实例
    }
    static aMethod2(){
        console.log('hi2')
    }
    aMethod1(){    //与静态方法重名了
        console.log('sup?')
    }
}
A.aMethod1()   //hi2
var a=new A()
a.aMethod1()   //sup?

父类的静态方法,可以被子类继承。

class A{
	static aMethod(){
		console.log('hi')
	}
}
class AA extends A{
}
AA.aMethod()  //hi

静态方法可以从super对象上调用的。

class A{
	static aMethod(){
		return `hi`
	}
}
class AA extends A{
    static aMethod(){
        console.log(`${super.aMethod()} , sup?`)
    }
}
AA.aMethod()  // hi , sup?

私有属性

私有属性只能在类的内部调用,在类的外部调用就会报错。引入一个新的前缀#表示私有属性。

class A{
    #val='value',
    sayValue(){
        console.log(this.#val)
    }
}
var a=new A()
console.log(a.#val)    //Private field '#val' must be declared in an enclosing class
console.log(a.sayValue())  //value

注意点

1、不存在变量提升

new A(); // ReferenceError
class A {}

2、es6默认就是严格模式

3、generator方法
在某个方法之前加上星号(*),就表示该方法是一个 Generator 函数。

class A {
  constructor(...args) {
    this.val = args;
  }
  * [Symbol.iterator]() {
    for (let arg of this.val) {
      yield arg;
    }
  }
}
for (let x of new A('a', 'b')) {
  console.log(x);
}
// a
// b

Symbol.iterator方法返回类的默认遍历器,for...of循环会自动调用这个遍历器。

4、this指向
类的方法内部如果含有this,它默认指向类的实例,但是类的内部采用的是严格模式,很容易报错。

class A{
    sayA(a='a'){
        this.log(a)
    }
    log(val){
        console.log(val)
    }
}
const a=new A()
const {sayA}=a;
sayA()   //Uncaught TypeError: Cannot read property 'log' of undefined

将方法提取出来单独使用,this会指向该方法运行时所在的环境(由于 class 内部是严格模式,所以 this 实际指向的是undefined),从而导致找不到方法而报错。

一个比较简单的解决方法是,在构造方法中绑定this,就不会找不到方法了。

class A{
    constructor(){
        this.sayA=this.sayA.bind(this)    //对方法进行绑定
        //this.sayA=()=>this       //通过箭头函数也可以实现。
    }
    sayA(a='a'){
        this.log(a)
    }
    log(val){
        console.log(val)
    }
}
const a=new A()
const {sayA}=a;
sayA()

上一篇: 2.ES6-新特性

下一篇: ES6中的“类”