浅谈ES6 中的Class

一、Class 的基本语法

静态方法与静态属性

\1. 不会被类实例所拥有的属性与方法 只是类自身拥有
\2. 只能通过类调用

静态方法与普通方法重名,不会冲突
static 关键字(静态方法)

静态属性
类名.属性名 = 属性值;

  • 静态属性的声明,应该在类外部,使用“类名.属性名”的方式声明。

  • 静态方法的调用,应该直接在类上调用,而不是在类的实例上调用。


1.静态方法

class Foo {				
	static baz(){
		console.log('hello');
	}
	baz(){
		console.log('world');
	}
}
class Bar extends Foo {
	static bar(){
		this.baz();
	}
}
Bar.bar(); //"hello"

上面代码中,Foo类的第一个baz方法前有static关键字,表明该方法是一个静态方法,可以直接在Foo类上调用(Foo.baz()),而不是在Foo类的实例上调用。如果在实例上调用静态方法,会抛出一个错误,表示不存在该方法。父类Foo有一个静态方法,子类Bar可以调用这个方法。静态方法bar调用了this.baz,这里的this指的是Foo类,而不是Foo的实例,等同于调用Foo.baz。另外,从这个例子还可以看出,静态方法可以与非静态方法重名。

  • 如果静态方法包含this关键字,这个this指的是类,而不是实例。

2.静态属性

 //职业类
    class Profession{

    }

    class Character {
        constructor(pfs) {
            this.pfs = pfs;
        }
    }
    // 静态属性做配置
    Character.config = {
        profession: {
            '法师': 1,
            '刺客': 2
        }
    }
    // 创建类的实例
    new Character(Character.config.profession['法师']);

上面的写法为Character类定义了一个静态属性config

3.私有方法

私有方法和私有属性,是只能在类的内部访问的方法和属性,外部不能访问。这是常见需求,有利于代码的封装,但 ES6 不提供,只能通过变通方法模拟实现。

class Widget {
  foo (baz) {
    bar.call(this, baz);
  }

  // ...
}

function bar(baz) {
  return this.snaf = baz;
}

将私有方法移出模块,因为模块内部的所有方法都是对外可见的。foo是公开方法,内部调用了bar.call(this, baz)。这使得bar实际上成为了当前模块的私有方法。

4.new.target

  • 判断构造函数是否通过new调用
class Shape {
  constructor() {
    if (new.target === Shape) {
      throw new Error('本类不能实例化');
    }
  }
}

class Rectangle extends Shape {
  constructor(length, width) {
    super();
    // ...
  }
}

var x = new Shape();  // 报错
var y = new Rectangle(3, 4);  // 正确

new.target的作用

------限制类的调用方法,判断new.target是不是未定义

-----可以写出不能独立使用、必须继承后才能使用的类。

上面代码中,Shape类不能被实例化,只能用于继承。

注意,在函数外部,使用new.target会报错。

二、Class 的继承

  • Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。

1.Object.getPrototypeOf()

Object.getPrototypeOf方法可以用来从子类上获取父类。

Object.getPrototypeOf(ColorPoint) === Point
// true

因此,可以使用这个方法判断,一个类是否继承了另一个类。

2.super关键字

  • ES6中,子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,然后再加上子类自己的实例属性和方法

在JavaScript中,this关键字总是指向函数所在的当前对象,ES6中增加了一个与this对应的super关键字,指向的是当前对象(this指向的对象)的原型对象。

    const demo1 = {
       prop1  : '属性1'
    };
     
    const demo2 = {
        find(){
           //返回demo2 的原型对象的foo属性
           return super.foo
        }
    };    
    Object.setPrototypeOf(demo2,demo1);
    obj.find() //"hello"

需要注意的是,当super关键字表示原型对象时,只能用在对象的方法中。而在这里JavaScript引擎有一个bug。只有用对象方法的简写写法时,引擎才能确认这个函数是对象的方法,其他写法应用super的时候都会报错。


    const proto = {
       title :'原型对象'
       sayTitle(){
          console.log(this.title);
       }
    };
    const obj = {
       title : '对象',
       sayPrototypeTitle(){
          super.sayTitle();
       }
    }
    Object.setPrototypeOf(obj,proto);obj.sayPrototypeTitle();// 结果:// 原型对象

下面是几种会报错的写法:

  
    //报错,因为super不能应用在方法之外。
    const obj = {
       protoTitle : super.foo
    }

    //因为此时JS引擎不能识别function是对象的方法,所以调用super会报错。
    const obj = {
       title : '对象',
       sayPrototypeTitle : function(){
          super.sayTitle();
       }
    }

    //因为此时JS引擎不能识别“箭头函数”是对象的方法,所以调用super会报错。
    const obj = {
       title : '对象',
       sayPrototypeTitle => super.sayTitle();
    }

2.Mixin模式的实现

Mixin 指的是多个对象合成一个新的对象,新对象具有各个组成成员的接口。它的最简单实现如下。

const a = {
  a: 'a'
};
const b = {
  b: 'b'
};
const c = {...a, ...b}; // {a: 'a', b: 'b'}

上面代码中,c对象是a对象和b对象的合成,具有两者的接口。

下面是一个更完备的实现,将多个类的接口“混入”(mix in)另一个类。

function mix(...mixins) {
  class Mix {
    constructor() {
      for (let mixin of mixins) {
        copyProperties(this, new mixin()); // 拷贝实例属性
      }
    }
  }

  for (let mixin of mixins) {
    copyProperties(Mix, mixin); // 拷贝静态属性
    copyProperties(Mix.prototype, mixin.prototype); // 拷贝原型属性
  }

  return Mix;
}

function copyProperties(target, source) {
  for (let key of Reflect.ownKeys(source)) {
    if ( key !== 'constructor'
      && key !== 'prototype'
      && key !== 'name'
    ) {
      let desc = Object.getOwnPropertyDescriptor(source, key);
      Object.defineProperty(target, key, desc);
    }
  }
}

上面代码的mix函数,可以将多个对象合成为一个类。使用的时候,只要继承这个类即可。

class DistributedEdit extends mix(Loggable, Serializable) {
  // ...
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值