简介
JavaScript 语言中,生成实例对象的传统方法是通过构造函数。下面是一个例子。
1 | function Point(x, y) { |
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class
关键字,可以定义类。
1 | //定义类 |
constructor
: 构造方法,类的默认方法,通过 new 命令生成对象实例时,自动调用该方法。- 一个类必须有 constructor 方法,如果没有显式定义,一个空的 constructor 方法会被默认添加。
this
: 关键对象
定义“类”的方法的时候,前面不需要加上 function 这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。
ES6 的类,完全可以看作构造函数的另一种写法。
1 | class Point { |
构造函数的prototype
属性,在 ES6 的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype
属性上面。
1 | class Point { |
在类的实例上面调用方法,其实就是调用原型上的方法。
1 | class B {} |
由于类的方法都定义在prototype
对象上面,所以类的新方法可以添加在prototype
对象上面。Object.assign 方法可以很方便地一次向类添加多个方法。
1 | class Point { |
类的属性名,可以采用表达式。
1 | let methodName = 'getArea' |
类的实例对象
与 ES5 一样,实例的属性除非显式定义在其本身(即定义在this
对象上),否则都是定义在原型上(即定义在class
上)。
1 | //定义类 |
hasOwnProperty
: 查找对象原型上是否有某属性 (上面代码表示 toString
保存在Point
类中,point 是通过原型链获得 toString
方法)
Class 表达式
与函数一样,类也可以使用表达式的形式定义。
1 | const MyClass = class Me { |
如果类的内部没用到的话,可以省略Me
,也就是可以写成下面的形式。
1 | const MyClass = class { |
采用 Class 表达式,可以写出立即执行的 Class。
1 | let person = new class { |
私有方法和私有属性
私有方法是常见需求,但 ES6
不提供,只能通过变通方法模拟实现。
在命名上加以区别:
1 | lass Widget { |
将私有方法移出模块,因为模块内部的所有方法都是对外可见的:
1 | class Widget { |
上面代码中,foo 是公有方法,内部调用了 bar.call(this, baz)。这使得 bar 实际上成为了当前模块的私有方法。
利用Symbol
值的唯一性,将私有方法的名字命名为一个Symbol
值:
1 | onst bar = Symbol('bar'); |
上面代码中,bar 和 snaf 都是 Symbol 值,导致第三方无法获取到它们,因此达到了私有方法和私有属性的效果。
this 的指向
类的方法内部如果含有this
,它默认指向类的实例。但是,必须非常小心,一旦单独使用该方法,很可能报错。
1 | class Logger { |
解决办法
- 在构造方法中绑定
this
1 | class Logger { |
- 箭头函数
1 | class Logger { |
- 使用
Proxy
,获取方法的时候,自动绑定this
1 | unction selfish (target) { |
getter setter
与 ES5 一样,在“类”的内部可以使用get
和set
关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
1 | class MyClass { |
存值函数和取值函数是设置在属性的 Descriptor 对象上的
Class 的 Generator 方法
todo // 对 Generator 不熟悉,待下次理解了在写
Class 的静态方法
静态方法:不会被实例继承,而是直接通过类来调用。
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上 static 关键字,就表示该方法不会被实例继承,而是直接通过类来调用
1 | class Foo { |
注意,如果静态方法包含
this
关键字,这个this
指的是类,而不是实例。
1 | class Foo { |
父类的静态方法,可以被子类继承。
1 | class Foo { |
静态方法也是可以从super
对象上调用的
1 | class Foo { |
Class 的静态属性和实例属性
静态属性:Class
本身的属性,即Class.propName
,而不是定义在实例对象(this
)上的属性。
1 | class Foo {} |
ES6 明确规定,Class 内部只有静态方法,没有静态属性
写法无效如下:
1 | // 以下两种写法都无效 |
类的实例属性
类的实例属性可以用等式,写入类的定义之中
1 | class MyClass { |
类的静态属性
类的静态属性只要在上面的实例属性写法前面,加上static
关键字就可以了。
1 | class MyClass { |