ES6 —(Class 的基本语法)

来源:互联网 发布:淘宝退货一般多久到账 编辑:程序博客网 时间:2024/06/10 15:02

1、简介

  JavaScript 生成实例对象的传统方法是通过构造函数。

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 关键字,可以定义类。

class PointClass{    constructor(x, y){        this.x = x;        this.y = y;    }    toString(){        return '(' + this.x + ', ' + this.y + ')';    }}var pc = new PointClass(1, 2);

  上述代码,可以看出,ES5 的构造函数 Point ,对应 ES6 的 Point 类的构造方法。 ES6 的 class 可以看做是一个语法糖,新的 class 写法只是让对象原型的写法更加清晰,更像面向对象编程的语法而已。

注意:
  (1)class 中定义方法的时候,前面不需要加 function 这个关键字。并且方法之间不需要逗号分隔,加了会报错。
  (2)类的数据类型是函数,函数本身就指向构造函数,即 ES6 的类,完全可以看做是构造函数的另一种写法。

typeof PointClass => functionPointClass === PointClass.prototype.constructor => true

  (3)类的所有方法都定义在类的 prototype 属性上面。(构造函数的 prototype )。
  (4)类的实例上面调用方法,其实就是调用原型上的方法。

pc.constructor === PointClass.prototype.constructor => true

  (5)类的内部所有定义的方法,都是不可枚举。这一点与 ES5 不一致。

Object.keys(PointClass.prototype);  => [] // 空Object.getOwnPropertyNames(PointClass.prototype);=> ["constructor", "toString"]Object.keys(Point.prototype); => ["toString"]Object.getOwnPropertyName(Point.prototype);=> ["constructor", "toString"]

  (6)类的属性名,可以采用表达式。使用表达式时要用中括号([])括起来。
  (7)类和模块的内部,默认就是严格模式,所以不需要使用 use strict 指定运行模式。 只要你的代码写在类或模块中,就只有严格模式可用。
  (8)类必须使用 new 调用,否则会报错。
  (9)与 ES5 一样,实例的属性除非显式定义在其本身(即定义在 this 对象上),否则都定义在原型上(即定义在 class 上)。
  (10)与函数一样,类也可以使用表达式的形式定义。采用 Class 表达式,可以写出立即执行的 Class 。

const Myclass = class Me{} // 这个类的名字是 MyClass 而不是 Me,// Me 只在 Class 的内部代码可用,指代当前类 const Myclass = class {}() // 立即执行的 Class

  (11)类不存在变量提升,所以必须先定义,后使用。

2、constructor 方法

  constructor 方法是类的默认方法,通过 new 命令生成对象实例时,自动调用该方法。一个类必须有 constructor 方法,如果没有显示定义,一个空的 constructor 方法会被默认添加。
  constructor 方法默认返回实例对象(即 this),完全可以指定返回另一个对象。

3、私有方法

  私有方法是常见需求,但 ES6 不提供,只能通过变量方法模拟实现。
  一种做法是在命名上加以区别,在私有方法前加下划线(如 _foo(){})。但是这种方法不保险,在类的外部还是可以调用到这个方法。
  另一种方法就是将私有方法移除模块,因为模块内部的所有方法都是对外可见的。

class Myclass {    foo(baz){        bar.call(this, baz);    }}function bar(baz){    return this.snaf = baz;}

上述方法, foo 是共有方法,内部调用了 bar, 这使得 bar 实际上成为了当前模块的私有方法。
  还有一种方法是利用 Symbol 值的唯一特性,将私有方法的名字命名为一个 Symbol 值。

4、私有属性

  与私有方法一样, ES6 不支持私有属性。目前,有一个提案,为 class 加了私有属性。方法是在属性名之前,使用 # 表示。

5、this 的指向

  类的方法内部如果含有 this ,它默认指向类的实例。
  需要注意的是,一旦单独使用了含有 this 的方法很可能会报错,因为单独使用时, this 会指向该方法的运行时所在的环境,这将导致属性或方法不存在而导致报错。

解决单独使用含有 this 的方法报错的方式
  (1)在构造函数中绑定 this, 这样就不会找不到属性或方法。

constructor(){    this.foo = this.foo.bind(this);}

  (2)使用箭头函数

constructor(){    this.foo = (x) => {this.x = x};}

  (3)使用 Poxy , 获取方法的时候,自动绑定 this

6、Class 的取值函数(getter)和存值函数(setter)

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

class MyClass {    get prop(){}    set prop(value){}}let my = new MyClass();my.prop = 123; => 执行 setter 方法my.prop; => 执行 getter 方法var descriptor = Object.getOwnProperDescriptor(MyClass, "prop");"get" in descriptor; => true"set" in descriptor; => true

7、Class 的静态方法和 Class 的静态属性

(1)Class 的静态方法
  类相当于实例的原型,所有类中定义的方法,都会被实例继承。如果在一个方法前,加上 static 关键字,就表示该方法不会被实例继承,而是直接通过类来调用(类名.方法名),这就称为“静态方法”。
注意:
  1)如果静态方法包含 this 关键字,这个 this 指的是类,而不是实例。
  2)父类的静态方法,可以被子类继承。
  3)静态方法可以使用 super 对象调用。

(2)Class 的静态属性
  类的静态属性指的是 Class 本身的属性,即 Class.propName ,而不是在实例对象(this)上的属性。目前只有一种定义静态属性的方法:

class Foo{}Foo.prop = 1;Foo.prop;

8、new.target 属性

  new 是从构造函数生成实例的命令。 ES6 为 new 命令引入了一个 new.target 属性,该属性一般用在构造函数之中,返回 new 命令作用于那个构造函数。如果构造函数不是通过 new 命令调用的, new.target 会返回 undefined ,因此可以用这个属性来确定构造函数是怎么调用的。
注意:
  1)Class 内部调用 new.target, 返回当前 Class。
  2)ES5 的构造函数中调用 new.target 返回当前构造函数
  3)子类继承父类时,通过子类调用父类,父类中的 new.target 会返回子类。

class Shape {    constructor() {        if (new.target === Shape) { // (1)            throw new Error('本类不能实例化');        }    }}class Rectangle extends Shape {    constructor(length, width) {        super();        // ...    }}var x = new Shape();  // (1)处为 true 所以报错var y = new Rectangle(3, 4);  // (1)处为 false 不报错 因为此时new.target === Rectangle    

  4)在函数外部,使用 new.target 会报错。
用途 通过该属性可以定义构造函数或者类只能通过 new 来实例,或者可以写出不能独立使用,必须继承后才能使用的类。 参照注意(3)。

阮一峰:ECMAScript 6入门