ES6 Class 的基本语法

ES6 Class

ES6(ECMAScript 2015)引入了类(Class)的概念,这是 JavaScript 编程中一个重要的特性,使得 JavaScript 可以更加面向对象地编程。ES6 Class 构建在 JavaScript 原型继承的基础上,提供了更清晰、更易于理解和使用的语法,使得创建对象和实现继承变得更加简洁和可读。

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

constructor()方法

class Animal {
  constructor(name) {
    this.name = name;
  }
  
  makeSound() {
    console.log("Animal sound");
  }
}

上面代码定义了一个“类”,可以看到里面有一个constructor()方法,这就是构造方法,而this关键字则代表实例对象。这种新的 Class 写法,本质上与 ES5 的构造函数是一致的。

下面是一个类使用 extends 关键字实现继承,一个类可以继承另一个类的属性和方法。

class Dog extends Animal {
  constructor(name, breed) {
    super(name); // 调用父类的构造函数
    this.breed = breed;
  }
  
  makeSound() {
    console.log("Woof woof");
  }
}

ES6 的类,完全可以看作构造函数的另一种写法。

class Animal{
  // ...
}

typeof Animal// "function"
Animal=== Animal.prototype.constructor // true

上面代码表明,类的数据类型就是函数,类本身就指向构造函数。

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

类的实例

class Bar {
  doStuff() {
    console.log('stuff');
  }
}

const b = new Bar();
b.doStuff() // "stuff"

由于类的方法都定义在prototype对象上面,所以类的新方法可以添加在prototype对象上面。Object.assign()方法可以很方便地一次向类添加多个方法。 

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

Object.assign(Animal.prototype, {
  toString(){},
  toValue(){}
});

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

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

与 ES5 一样,类的所有实例共享一个原型对象。

var p1 = new Animal(2,3);
var p2 = new Animal(3,2);

p1.__proto__ === p2.__proto__
//true

实例属性的一种新写法

ES2022 为类的实例属性,又规定了一种新写法。实例属性现在除了可以定义在constructor()方法里面的this上面,也可以定义在类内部的最顶层。

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

使用getset关键字

class Temperature {
  constructor(celsius) {
    this.celsius = celsius;
  }

  // Getter 方法将摄氏温度转换为华氏温度
  get fahrenheit() {
    return (this.celsius * 9/5) + 32;
  }

  // Setter 方法用于设置摄氏温度,同时更新华氏温度
  set celsius(value) {
    if (value < -273.15) {
      throw new Error("Temperature is too low.");
    }
    this._celsius = value;
  }

  get celsius() {
    return this._celsius;
  }
}

const temp = new Temperature(25);

console.log(temp.celsius);     // 输出:25
console.log(temp.fahrenheit);  // 输出:77

temp.celsius = 30; // 设置摄氏温度,同时更新华氏温度
console.log(temp.celsius);     // 输出:30
console.log(temp.fahrenheit);  // 输出:86

// 尝试设置超低温度,会触发错误
try {
  temp.celsius = -300;
} catch (error) {
  console.log(error.message); // 输出:Temperature is too low.
}

与 ES5 一样,在“类”的内部可以使用getset关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。

属性名采用表达式

let methodName = 'getArea';

class Square {
  constructor(length) {
    // ...
  }

  [methodName]() {
    // ...
  }
}

 上面代码中,Square类的方法名getArea,是从表达式得到的。

类表达式

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

const MyClass = class Me {
  getClassName() {
    return Me.name;
  }
};

上面代码使用表达式定义了一个类。需要注意的是,这个类的名字是Me,但是Me只在 Class 的内部可用,指代当前类。在 Class 外部,这个类只能用MyClass引用。 

静态方法和静态属性

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”

通过在方法前面使用 static 关键字,你可以创建一个静态方法。静态方法不会被实例继承,而是直接属于类本身。这意味着它们不能在类的实例上调用,而是通过类本身调用。

class Foo {
  static classMethod() {
    return 'hello';
  }
}

Foo.classMethod() // 'hello'

var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function

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

class Foo {
}

Foo.prop = 1;
Foo.prop // 1

 上面的写法为Foo类定义了一个静态属性prop

私有方法和私有属性

在传统的 JavaScript 中,没有像其他编程语言中那样的严格的私有方法和私有属性的概念。然而,可以使用一些约定和技巧来模拟私有性。ES6(ECMAScript 2015)引入的一些功能也使得实现更接近私有性成为可能。

私有方法和私有属性,是只能在类的内部访问的方法和属性,外部不能访问。这是常见需求,有利于代码的封装,但早期的 ES6 不提供,只能通过变通方法模拟实现。

一种做法是在命名上加以区别。

class Widget {

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

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

  // ...
}

另一种方法就是索性将私有方法移出类,因为类内部的所有方法都是对外可见的。

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

  // ...
}

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

 还有一种方法是利用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;
  }

  // ...
};

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

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

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

const counter = new IncreasingCounter();
counter.#count // 报错

当然使用闭包可以模拟真正的私有性,因为闭包中的变量只在函数内部可见。 

function createCounter() {
  let count = 0;

  return {
    increment: function() {
      count++;
    },

    getCount: function() {
      return count;
    }
  };
}

const counter = createCounter();
counter.increment();
console.log(counter.getCount()); // 输出 1
console.log(counter.count); // undefined,count 是私有的

使用 ES6 引入的 Symbol 数据类型可以用于创建唯一的键,从而模拟私有属性。

const _privateKey = Symbol("privateKey");

class MyClass {
  constructor() {
    this[_privateKey] = "This is a private value.";
  }

  getPrivateValue() {
    return this[_privateKey];
  }
}

const instance = new MyClass();

console.log(instance.getPrivateValue()); // 可以获取私有值
console.log(instance[_privateKey]); // 但是无法直接访问,因为私有键是 Symbol 类型

 

 Class 的基本语法 - ECMAScript 6入门 (ruanyifeng.com)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ikkkp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值