前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ES6—class类详细教程(下)

ES6—class类详细教程(下)

作者头像
用户9999906
发布2022-09-26 11:43:59
7020
发布2022-09-26 11:43:59
举报
文章被收录于专栏:学编程的GISer

上一期出了ES6中Class类用法详解的(上)半部分,以下是(下)半部分,需要复习上半部分的小伙伴可以点击文章末尾的“阅读原文”或者点击文中的超链接。

本期目录:

Class的常见语法(下)

请大家仔细阅读文中的代码块,尤其是注释部分

7. 静态方法

Class的常见语法(上)我们知道,class关键字定义的类中有的方法,在这个类创建出来的对象上都可以使用,比如:

代码语言:javascript
复制
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  toString() {
    return `我叫${this.name},今年${this.age}了`;
  }
  showName() {
    return this.name;
  }
}

const person = new Person('大潘', 101);
console.log(person.toString());// 我叫大潘,今年101了
console.log(person.showName());// 大潘

但是如果在Class中的方法前加上static关键字,那这个方法就不会被继承,只能通过类来调用,这样的方法称为"静态方法":

代码语言:javascript
复制
class Person {
  // ...
  static classMethod() {
    return '我是一个Person类的方法,对象不能用哦';
  }
  objectMethod() {
    return '我虽然是Person类上的方法,但是被我创建出来的对象也可以用我哦';
  }
}

const person = new Person('大潘', 99);
console.log(Person.classMethod());// 我是一个Person类的方法,对象不能用哦
console.log(person.classMethod());// 报错:TypeError: person.classMethod is not a function
console.log(person.objectMethod());// 我虽然是Person类上的方法,但是被我创建出来的对象也可以用我哦

我们发现,“静态方法”只能被类调用,用类的实例对象调用的话会报错,表示不存在该方法,验证:

静态方法:

静态方法验证

非静态方法:

原型方法验证

而且,如果静态方法中包含this关键字,那么这个this指向类,而不是实例:

代码语言:javascript
复制
class Person {
  // ...
  static classMethod() {
    console.log(this);
    return '我是一个Person类的方法,对象不能用哦';
  }
  // ...
}

Person.classMethod();// class Person{ //代码 },打印的是Person类

父类上的静态方法可以继承到其子类上(比如Son类继承了Person类,那么Son类可以通过Son.classMethod()来调用这个方法),之后我会专门出一期Class的继承

8. 静态属性

Class的“静态属性”和“静态方法”类似,都是只有Class才能调用,如果由这个Class创建出来的实例对象调用会报错。

之前,在Class内部添加静态属性的方法是:

代码语言:javascript
复制
class Person {}
Person.a = 1;
console.log(Person.a);// 1

因为ES6明确规定Class内部只有静态方法,没有静态属性,但是现在有一个提案提供了Class的静态属性,写法是在实例属性前加上static关键字:

代码语言:javascript
复制
class Person {
  static a = 2;
}
console.log(Person.a);// 2

这种显示声明静态属性的方法一定程度上方便了静态属性的表达。

与Class的“静态方法”一样,“静态属性”也会被继承到其子类上:

代码语言:javascript
复制
class Person {
  static a = 3;
}
class Son extends Person {}
console.log(Son.a);// 3

9. 私有属性和私有方法

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

(1)私有属性

在ES2022中,提出了在属性名前加#表示Class的私有属性:

代码语言:javascript
复制
class Person {
  #name = '大潘';
  name = 'Dapan';
  getName() {
    return `${this.#name}的英文名叫${this.name}`;
  }
}

const person2 = new Person();
console.log(person2.#name);//报错:Uncaught SyntaxError: Private field '#name' must be declared in an enclosing class
console.log(person2.age);// Dapan
console.log(person2.getName());// 大潘的英文名叫Dapan

上边代码表示,在Person类的外部调用带有#的私有属性会报错,调用不带#的属性不会报错。但是在Person内部调用#name属性不会报错。由于井号#是属性名的一部分,使用时必须带有#一起使用,所以#namename是两个不同的属性。另外,私有方法也可以设置getter和setter,方法与非私有属性一样,上一篇推文已经讲过,不再赘述。

(2)私有方法

在设置Class中私有方法的,Dapan推荐使用以下方式:

代码语言:javascript
复制
class Person {
  // ...
  #getName() { // 和私有属性一样,在方法名前加‘#’表示私有方法
    // ...
  }
}

上面代码中,#getName()就是一个私有方法,它只可以在Person类的内部使用,在外部使用会报错:

代码语言:javascript
复制
class Person {
  // ...
  #getName() {
    console.log('我是Person类的私有方法');
  }
}

Person.prototype.#getName();// 这里并没有打印出来'我是Person类的私有方法',而是报错:
                            // Uncaught SyntaxError: Private field '#getName' must be declared in an enclosing class

(PS:私有属性和私有方法也可以加static关键字成为静态的私有属性和方法)

10. in运算符

当我们访问某个类不存在的私有属性的时候会报错,但是访问不存在的共有属性并不会报错:

代码语言:javascript
复制
class Person {}

const person3 = new Person()
console.log(person3.test);// undefined
console.log(person3.#test);// 报错:Uncaught SyntaxError: Private field '#test' must be declared in an enclosing class

我们可以根据这一特性,利用in运算符,判断某个对象是否为类的实例(判断这个对象上是否有这个类的私有属性,如果报错,则表示这个对象不是这个类的实例,反之则是):

代码语言:javascript
复制
class Person {
  #name = 'Dapan';
  // ...
  static isNameInPersonClass(obj) {
    if (#name in obj) {
      return '这个对象是Person类的实例';
    } else {
      return '这个对象不是Person类的实例';
    }
  }
}

const person4 = new Person();
const person5 = Object.create(null);
console.log(Person.isNameInPersonClass(person4)); // 这个对象是Person类的实例
console.log(Person.isNameInPersonClass(person5)); // 这个对象不是Person类的实例

想一下,我这里为什么要在Person类里定义一个静态方法来辅助判断person4person5这两个对象是否为Person类的实例对象?如果要用普通方法进行判断该怎么写?

子类从父类继承的私有属性,也可以使用in运算符来判断:

代码语言:javascript
复制
class Person {
  #name = 'dapan';
  static test(obj) {
    return #name in obj;
  }
}

// 定义Son类继承Person类:
class Son extends Person {}
const son = new Son();
const obj = Object.create(null);
console.log(Person.test(son)); // true 
console.log(Person.test(obj)); // false

有一点需要注意:in运算符只能用在类的内部。

10. 静态块

每个类只能有一个静态块,在静态属性声明后运行。静态块的内部不能有return语句,且静态块只运行一次。静态块内部可以使用类名或this,指代当前类。

可以通过静态块将私有属性传递到类的外部

代码语言:javascript
复制
let getAge;
class Person {
  #age = 101;
  // ...
  static {
    getAge = (obj) => obj.#age;
  }
}

const person7 = new Person();
console.log(getAge(person7));// 打印101,拿到了Person类内部的私有属性

上面示例中,#age是类的私有属性,如果类外部的getAge()方法希望获取这个属性,以前是要写在类的constructor()方法里面,这样的话,每次新建实例都会定义一次getAge()方法。现在可以写在静态块里面,这样的话,只在类生成时定义一次。

11. 类的注意点

(1)类的声明不存在提升

ES6中,Class的声明不存在提升,这一点与ES5完全不同:

代码语言:javascript
复制
// ES5:
new Person(); // 不报错
function Person() {}

// ES6:
new Person(); // 报错:Uncaught SyntaxError: Identifier 'Person' has already been declared
class Person {}

这样的规定是为了保证Class在继承(下下期推文会出“Class的继承”)的时候,子类在父类之后定义。

(2)name属性

获取类的名字:

代码语言:javascript
复制
class Person {}
console.log(Person.name); // Person

(3)this指向

一般情况下,类的方法中如果包含this,它默认指向类的实例对象:

代码语言:javascript
复制
class Person {
  name = 'dapan';
  lookThis() {
    return this;
  }
}

const person8 = new Person();
console.log(person8.lookThis());// 打印Person构造的实例对象:person8, {name: 'dapan'}

但是也有例外,比如单独使用该方法,this的指向为undefined:

代码语言:javascript
复制
class Person {
  name = 'dapan';
  lookThis() {
    return this;
  }
}

const person8 = new Person();
const { lookThis } = person8;
console.log(lookThis());// undefined

此时的this指向该方法运行时所在的环境(由于class内部是严格模式,所以此时this指向的是undefined)。

解决办法就是,提前给lookThis()方法绑定this:

代码语言:javascript
复制
class Person {
  name = 'dapan';
  // 绑定lookThis方法的this:
  lookThis = this.lookThis.bind(this);
  lookThis() {
    return this.name;
  }
}

const person8 = new Person();
const { lookThis } = person8;
console.log(lookThis()); // dapan

还有一种更简单的方法,使用箭头函数。因为箭头函数内部的this总是指向定义时所在的对象。上面代码中,箭头函数位于构造函数内部,它的定义生效的时候,是在构造函数执行的时候。这时,箭头函数所在的运行环境,肯定是实例对象,所以this会总是指向实例对象。相当于自动帮我们绑定了this:

代码语言:javascript
复制
class Person {
  name = 'dapan';
  lookThis = () => { // 使用箭头函数
    return this.name;
  };
}

const person8 = new Person();
const { lookThis } = person8;
console.log(lookThis()); // dapan

(完)

以上内容均为Dapan阅读文章教程之后,花了4个多小时的个人整理,主要参考资料如下:

https://es6.ruanyifeng.com/#docs/class#%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-07-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 学编程的GISer 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Class的常见语法(下)
    • 7. 静态方法
      • 8. 静态属性
        • 9. 私有属性和私有方法
          • (1)私有属性
          • (2)私有方法
        • 10. in运算符
          • 10. 静态块
            • 11. 类的注意点
              • (1)类的声明不存在提升
              • (2)name属性
              • (3)this指向
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档