掌握Javascript(七)

本文介绍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的最后一篇,敬请期待。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注