本文介绍ES6中的类
ES6的class
ES6新增了一个class,但这个class与C#、Java不同,只是为了实现类似类继承而套的一层皮,实际还是原型继承。
class Circle {constructor(radius) {
this.radius = radius;
this.move = function () {};
// 这个move方法是实列方法
}
draw() {}
// 这里前面不加function,属于原型方法
// 如果不想用原型方法,定义在构造器constructor就行
}
这种写法与Java、C#等很类似。
用typeof(Circrl)检查,发现实际还是 function 的。
- 访问:https://babeljs.io,可以将新版本的Javascript代码转换成旧版本的Javascript代码,以便所有浏览器都可以识别。
- ES6要求构造函数前必须使用new,否则将出错。
置顶Hoisting
前面在介绍函数时说过,函数有两种方式:
- 函数声明,如 function sayHello(){}
- 函数表达式,如 const sayHello=function(){};
函数表达式后面有分号,两者的区别是函数声明是置顶的,可以在声明之前调用它,而函数表达式则不可以,只能在表达式之后调用。
同样的,类也有两种方法:声明和表达式。
- 类声明。class Circle {}
- 类表达式。const Square = class{};
建议使用类声明方式,几乎不会有人用类表达式!
不管类声明和类表达式,都不会置顶,这与函数是不同的。
静态方法
经典类中有两种方法:实例方法和静态方法。实例方法属于对象的方法,而静态方法不属于特定对象,属于类,调用在类层面。Javascript也有静态方法。
class Circle {
…
draw() {}
static parse(str) {
// 方法前面加 static 即为静态方法
const radius = JSON.parse(str).radius;return new Circle(radius);
}
}
// 调用,注意是用类名调用,具体对象是没有这个静态方法的
const circle = Circle.parse(‘{“radius”:1}’);
静态对象是不属于具体实例的工具函数。
一些内建对象如Math,不用创建对象就可以调用方法,这些方法都是静态方法。
this关键字
对象调用方法,this指向调用的对象。如果是函数调用,则指向全局对象,如浏览器的window对象或node的Global对象。
为了防止错误指向了全局对象,可以使用严格模式,做法是在js文件里(比如首行)加上一句,即可使指向全局的变成undefined。
‘use strict’;
在ES6下,不管有没有使用 ‘use strict’,都是使用严格模式的。
class Circle {draw() {
console.log(this);}
}
const c = new Circle();
const draw = c.draw;
draw();
// 将显示 undefined,而不是全局对象,
// 因为ES6默认开启了严格模式。
使用Symbols的私有属性
命令习惯:前面加下划线,如 _radius,但这只是约定,外部还是能访问,不能算是一种方法。
ES6的Symbols一种是新型的值类型,它是一个函数调用,每次调用产生不同的值,如Sysbols()===Symbols()为false。
const _radius = Symbol();
class Circle {
constructor(radius) {
this[_radius] = radius;
}
}
const c = new Circle(1);
// 外部就不能访问 c[_radius]的值了,起到私有属性的功能
console.log(Object.getOwnPropertyNames(c));
// 用 getOwnPropertyNames也只能得到空数组,说明没有可见的属性
当然,如果一定要查看,也是有方法的。
const key = Object.getOwnPropertySymbols(c)[0];
// 得到第一个Symbol,然后通下面语句读到该属性值
console.log(c[key]);
但一般人不会这么做,所以用Symbol基本能起到不错的隐藏属性的功能。
隐藏方法与属性类似:
const _draw = Symbol();
…
class Circle {
…
[_draw]() {
// 方括号包起来作为一个方法命名
console.log(“Symbol function.”);
}
}
使用弱映射(WeakMap)的私有属性
可以使用WeakMap实现私有属性。
const _radius = new WeakMap();
// 私有属性用
const _move = new WeakMap();
// 私有方法用
class Circle {
constructor(radius) {
_radius.set(this, radius);
// 第一个参数为对象,传入this,私有属性
_move.set(this, () => {
console.log(“move”, this);
});
// 这里没用function(){},而是用箭头函数()={},
// 主要是避免函数体内的this指向全局undifined
}
draw() {
_move.get(this)();
// 调用私有方法
console.log(“draw”);}
}
const c = new Circle(1);
有人喜欢将弱映射私有方法放在一个变量里,比如:
const privateProps = new WeakMap()
class Circle {
constructor(radius) {
privateProps.set(this,{
radius:radius,
move:()=>{}
});
}
// …
}
调用:privateProps.get(this).radius
这种将弱映射全放在一个变量的方法不够清晰,个人建议每一个变量用一个WeakMap。
Getter 和 Setter
ES6中写法简化很多,简单加set、get即可。
const _radius = new WeakMap();
class Circle{
constructor(radius){
_radius.set(this,radius);
}
get radius(){
// 加 get,表示属性读取
return _radius.get(this);
}
set radius(value){
// 加 set,表示设置属性
if(value<=0) throw new Error(‘invalid radius’);
_radius.set(this,value);
}
}
const c = new Circle(1);
c.radius=10
console.log(c.radius)
// 注意调用不加小括号(),表示是属性,不是方法
继承
ES6中也简化了继承的语法,用extends就可以了。
class Shape {
constructor(color) {
this.color = color;
}
move() {
console.log(“move”);
}
}
class Circle extends Shape {
// extends表示继承
constructor(color, radius) {
super(color);
this.radius = radius;
}
draw() {
console.log(“draw”);
}
}
const c = new Circle(“red”, 1);
c 对象有radius和red属性,以及draw()和move()方法
方法重写
看代码。
class Shape {
move() {
console.log(“move”);
}
}
class Circle extends Shape {
move() {
// 重写基类的move方法
super.move();
// 如果需要调用基类方法,加上super前缀
console.log(“Circle move”);
}
}
const c = new Circle();
c.move();
小结
本文介绍了ES6的类,它不是真正的类,只是在原型继承外面包了一层皮。
下一篇计划介绍ES6中的工具,也是Javascript的最后一篇,敬请期待。