Es6-class类详解

Es6-class类详解

ES6 引入了Class(类)这个概念,作为对象的模板,通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码用ES6的“类”改写,就是下面这样。

1. 基本语法

定义一个类

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

const p = new Point(1,2)

上面代码,我们定义了一个Point类,可以看见里面有一个constructor方法,这个就是构造函数,this关键字就是当前的实例对象

使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致。

Point类除了构造方法,还定义了一个toString()方法,定义toString()方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了,方法与方法之间不需要逗号分隔。

class Point {
  
}
typeof Point // "function"
Point === Point.prototype.constructor // true

在上面代码中我们使用typeof去查看我们的Point是什么类型,出来的结果是函数,类的数据类型就是函数,类本身就指向构造函数。

class Point {
  constructor() {
    // ...
  }

  toString() {
    // ...
  }

  toValue() {
    // ...
  }
}

// 等同于

Point.prototype = {
  constructor() {},
  toString() {},
  toValue() {},
};

上面代码中,constructor()toString()toValue()这三个方法,其实都是定义在Point.prototype上面。

class B {}
const b = new B();

b.constructor === B.prototype.constructor // true

上面代码中,bB类的实例,它的constructor()方法就是B类原型的constructor()方法。

因为类方法都是定义在prototype上,所以我们可以直接添加在原型上

class B {}
B.prototype.fun = ()=>{}
B.prototype.ron = ()=>{}

prototype对象的constructor属性,直接指向“类”的本身,这与 ES5 的行为是一致的。

Point.prototype.constructor === Point // true

constructor方法

constructor()是类的自带的一个方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor()方法,如果没有显式定义,一个空的constructor()方法会被默认添加,所以即使你没有添加构造函数,也是有默认的构造函数的。一般constructor方法默认返回实例对象this,但是也可以指定constructor方法返回一个全新的对象,让返回的实例对象不是该类的实例。

 //使用class声明一个类
        class Person{
            //每个类都有构造方法constructor,实例化对象时执行构造方法
            //即使你不写构造方法,浏览器也会自动补全,但没有可执行的内容。
            constructor(name,age){
                //这里的this类似于构造函数中返回的实例对象。
                //一般在构造方法中定义属性,不定义方法
                this.name = name;
                this.age = age;
            }
            //这里定义方法等同于在构造函数的原型上定义方法,是实例的共同方法
            speak(){
                console.log('speak');
            }
        }
        //实例化一个Person对象:
        const p1 = new Person('小明',18);
        const p2 = new Person('小猪',19);
        const v = `${p1.name},${p1.age},${p2.name},${p2.age}`;
        console.log(v)//小明,18,小猪,19
        console.log(p1.speak == p2.speak); //true

类的两种定义方式

 //类的两种定义方式
        //一、声明形式
        class Person1{
            constructor(){}
            speak(){}
        }
        //二、表达式形式
        const Person2 = class{
            constructor(){}
            speak(){}
        }

实例的属性和方法

 class Person1{
            age = 0;
            sex = 'male';
            constructor(){}
            speak(){
                return "我是speak"
            }
        }
        const per1 = new Person1();
        const per2 = new Person1();
        console.log(per1.age,per1.hasOwnProperty("age"));//0 true
        console.log(per2.speak(),per2.hasOwnProperty("speak"),Person1.prototype.hasOwnProperty("speak"));//我是speak false true

静态属性和方法(类的属性和方法)

静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。

声明静态方法:在方法名前加static

class MyClass {
  static myStaticProp = 42;

  constructor() {
    console.log(MyClass.myStaticProp); // 42
  }
}
const MyClass = class{
            constructor(){}

            static speak(){
                console.log('静态');
                console.log(this); //this指向class
            }
        }
        //调用静态方法:由类调用
        MyClass.speak()

私有属性和方法

什么是私有:

只能在类的内部访问的方法和属性,外部不能访问。

为什么需要私有属性和方法

类的属性和方法都是公开的,公有的属性和方法可以被外界修改,造成意想不到的错误,所以需要私有属性

class Widget {

  // 公有方法
  foo (baz) {
    this._bar(baz);
  }

  // 私有方法
  _bar(baz) {
    return this.snaf = baz;
  }

  // ...
}

上面代码中,_bar()方法前面的下划线,表示这是一个只限于内部使用的私有方法。但是,这种命名是不保险的,在类的外部,还是可以调用到这个方法。

另一种方法将私有属性和方法移出类

class Widget {
  foo (baz) {
    bar.call(this, baz);
  }

  // ...
}

function bar(baz) {
  return this.snaf = baz;
}

上面代码中,foo是公开方法,内部调用了bar.call(this, baz)。这使得bar()实际上成为了当前类的私有方法。

//Person.js
            let name = "";
            class Person{
                constructor(username){
                    //name是类的属性不是实例的属性
           // console.log(Person.hasOwnProperty("name")) true
                    name = username;
                  
                }
                speak(){
                    console.log('speak');
                }
                getName(){
                    return name;
                }
            }
            //暴露Person
            window.Person = Person;
//index.js
            const p = new Person('Alex');
            console.log(p.getName()); //Alex
           // console.log(p.hasOwnProperty("name")) false

还有一种方法是利用Symbol值的唯一性,将私有方法的名字命名为一个Symbol值。

const bar = Symbol('bar');
const snaf = Symbol('snaf');

export default class myClass{

  // 公有方法
  foo(baz) {
    this[bar](baz);
  }

  // 私有方法
  [bar](baz) {
    return this[snaf] = baz;
  }

  // ...
};

上面代码中,barsnaf都是Symbol值,一般情况下无法获取到它们,因此达到了私有方法和私有属性的效果。但是也不是绝对不行,Reflect.ownKeys()依然可以拿到它们。

ES2022正式为class添加了私有属性,方法是在属性名之前使用#表示。

class IncreasingCounter {
  #count = 0;
  get value() {
    console.log('Getting the current value!');
    return this.#count;
  }
  increment() {
    this.#count++;
  }
}

然可以拿到它们。

ES2022正式为class添加了私有属性,方法是在属性名之前使用#表示。

class IncreasingCounter {
  #count = 0;
  get value() {
    console.log('Getting the current value!');
    return this.#count;
  }
  increment() {
    this.#count++;
  }
}

上面代码中,#count就是私有属性,只能在类的内部使用(this.#count)。如果在类的外部使用,就会报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值