💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## Class ### 简介 在ES6之前,JavaScript通过构造函数定义并生成新对象: ```js function Point(x, y) { this.x = x this.y = y } Point.prototype.toString = function () { return '(' + this.x + ', ' + this.y + ')' } var p = new Point(1, 2) ``` ES6引入了 `Class` (类)这个概念作为对象的模板,通过 `class` 关键字可以定义类。基本上,它可以看做是一个语法糖。将上面的定义改写: ```js class Point { constructor(x, y) { this.x = x this.y = y } toString() { return `(${this.x}, ${this.y})` } } ``` `constructor` 方法是构造方法,而 `this` 关键字则代表实例对象。 使用的时候也是直接对类使用 `new` 命令,跟构造函数的用法一致。 ```js class Bar { doStuff() { console.log('stuff') } } var b = new Bar() b.doStuff() // 'stuff' ``` 构造函数的 `prototpye` 属性在ES6的类上继续存在,类的所有方法都定义在 `prototpye` 属性上。 ### 严格模式 类和模块的内部默认使用严格模式,所以不需要使用 `use strict` 指定运行严格模式。 ### constructor方法 `constructor` 方法是类的默认方法,通过 `new` 命令生成对象实例时自动调用该方法。一个类必须有 `constructor` 方法,如果没有显式的定义,一个空的 `constructor` 方法会被默认添加。 ```js class Point {} // 等同于 class Point { constructor () {} } ``` `constructor` 方法默认返回实例对象(即`this`). ```js class Foo { constructor () { return Object.create(null) } } new Foo() instanceof Foo // false ``` ### 类的实例对象 生成实例对象的写法跟ES5一致,也是使用 `new` 命令。 ### Class表达式 与函数一样,`Class` 也可以使用表达式的形式定义 ```js const MyClass = class Me { getClassName () { return Me.name } } ``` 注意上面的代码,这个类的名字是`MyClass`,而不是`Me`。 ### 不存在变量提升 类不存在变量提升。 ```js new Foo() // 报错 ReferenceError class Foo {} ``` ### 私有方法 ES6不提供私有方法,可以通过其他方法来模拟实现 一种方法时通过命名加以区别: ```js class Widget { // 公有方法 foo (baz) { this._bar{baz} } // 私有方法 _bar(baz) { return this.snaf = baz } } ``` 上面的代码使用一个下划线来标明这个方法是私有方法,但这种命名是不保险的,在类的外部依然可以调用这个方法。 另一种方法时将私有方法移出模块,因为模块内部方法对外都是可见的。 ```js class Widget { foo (baz) { bar.call(this, baz) } // ... } function bar(baz) { return this.snaf = baz } ``` 还有一种方法,是利用`Symobl`值得唯一性将私有方法的名字命名为一个`Symbol`值。 ```js const bar = Symbol('bar') const snaf = Symbol('snaf') export default class myClass { // 公有方法 foo (baz) { this[bar] (baz) } // 私有方法 [bar](baz) { return this[snaf] = baz } } ``` ### 私有属性 ES6也不支持类的私有属性。目前,有一个提案是为`Class`加入私有属性。方法是在属性名之前,使用`#`来表示。 ```js class Point { #x constructor (x = 0) { #x = +x } } ``` ### this的指向 类的方法内部如果还有`this`,它将默认指向类的实例。 ### Class的取值函数(getter)和存值函数(setter) 在类的内部可以使用`get`和`set`关键字对某个属性设置存值函数和取值函数,拦截该属性的存取行为。 ```js class MyClass { constructor () { // ... } get prop() { return 'getter' } set prop(value) { console.log('setter: ' + value) } } let inst = new MyClass() inst.prop = 123 // setter: 123 inst.prop // getter ``` ### Class的Generator方法 如果某个方法之前加上星号(*),就表示这个方法时一个`Generator`函数 ```js class Foo { constructor (...args) { this.args = args } * [Symbol.iterator]() { for (let arg of this.args) { yield arg } } } for (let x of new Foo('hello', 'world')) { console.log(x) } // hello // wolrd ``` ### Class的静态方法 如果在一个方法前加上`static`关键字,就表示该方法不会被实例继承,而是通过类调用,这称为"静态方法" ```js class Foo { static classMethod() { return 'hello' } } Foo.classMethod() // 'hello' var foo = new Foo() foo.classMethod() // TypeError ``` 父类的静态方法可以被子类继承 ```js class Foo { static classMethod() { return 'hello' } } class Bar extends Foo {} Bar.classMethod() // 'hello' ``` ### Class的静态属性和实例属性 静态属性指的是`Class`本身的属性,即`Class.propname`,而不是定义在实例对象(this)上的属性。 ```js class Foo {} Foo.prop = 1 Foo.prop // 1 ``` 目前只有像上面的代码那样去给一个类定义静态属性,而不能像定义静态方法那样定义静态属性。 #### Class的实例属性 `Class`的实例属性可以用等式写入类的定义之中。 ```js class MyClass { myProp = 42 constructor() { console.log(this.myProp) // 42 } } ``` #### Class的静态属性 `Class`的静态属性只要在实例属性的定义写法前面加上`static`即可。 ```js class MyClass { static myStaticProp = 42 constructor() { console.log(MyClass.myStaticProp) // 42 } } ```