ES6中类的使用

520 阅读5分钟

ES6中类的使用

class定义类的方式

// 类的声明
class Person {
  
}

// 类的表达式(了解)
// var Animal = class {
// }

// 类的特点: 类内部的原型实现与函数的原型实现一致
console.log(Person.prototype.constructor); // [class Person]
console.log(Person.prototype.__proto__ === Object.prototype) // true
console.log(Function.__proto__ === Function.prototype) // true
console.log(typeof Person) // function
 
var p = new Person()
console.log(p.__proto__ === Person.prototype) // true

class的构造方法

// 类的声明
class Person {
  // 类的构造方法
  constructor(name, age) {
    this.name = name // this就是p1
    this.age = age
  }
}

// new关键字操作类时,调用constructor函数
var p1 = new Person('Fhup', 18)
var p2 = new Person('Fhf', 20)
console.log(p1.name);
console.log(p2.name);

class中方法的定义

class Person {
  constructor(name) {
    this.name = name
    this._address = '北京市'
  }
  // 普通的实例方法
  eat() {
    console.log(this.name + ' 在吃汉堡!');
  }
  // 类的访问器方法 set/get
  // 等价于Person.prototype上添加address属性
  get address() {
    console.log('进行其他的操作!');
    return this._address
  }
  set address(value) {
    this._address = value
  }
  // 类的静态方法 (类方法)
  static createNewPerson(){
    return new Person('bobo')
  }
}

var p1 = new Person('Fhup')
p1.eat()

console.log(p1.address)
p1.address = '宝鸡市'
console.log(p1.address)

var newperson = Person.createNewPerson()
console.log(newperson) // Person { name: 'bobo', _address: '北京市' }


// 所以eat()放在Person的prototype上,实现共享
console.log(Object.getOwnPropertyDescriptors(Person.prototype))

class中实现继承

class Father {
  constructor(name, age){
    this.name = name
    this.age  = age
  }
  eat(){
    console.log(this.name + ' eat~');
  }
  // 静态方法存在于类中,静态方法也可以被重写
  static xxx(){} 
}
// Son称之为子类(派生类)
class Son extends Father {
  // JS引擎在解析子类时要求我们必须使用super(),在this之前调用
  constructor(name, age, toy){
    super(name, age)
    this.toy = toy
  }
  play(){
    console.log(this.name + ' play gun!');
  }

  // 对父类方法的重写
  eat(){ 
    super.eat() // 可以调用父类的方法(通过super关键字)
    console.log(this.name + ' eat milk~');
  }
}

var s1 = new Son('Fhup', 18, '枪')
console.log(s1);
s1.eat()
s1.play()


// 测试原型
// console.log(Object.getOwnPropertyDescriptors(s1.__proto__)); // 有play()
// console.log(s1.__proto__ === Son.prototype) // true

// 注意: Son.prototype的 __proto__ 指向 Father.prototype, 因为进行了继承
// console.log(Object.getOwnPropertyDescriptors(s1.__proto__.__proto__)); // 有eat()
// console.log(s1.__proto__.__proto__ === Father.prototype) // true
// console.log(Father.prototype.__proto__) // [Object: null prototype] {}

ES6转ES5的代码

class Person{
  constructor(name){
    this.name = name
  }
  eat(){
    console.log(eat)
  }
}

// babel转换后的代码  网址: https://babeljs.io/
"use strict";
// 这个方法检测this是不是new Person()创建出来的
function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

function _defineProperties(target, props) {
  for (var i = 0; i < props.length; i++) {
    var descriptor = props[i];
    descriptor.enumerable = descriptor.enumerable || false;
    descriptor.configurable = true;
    if ("value" in descriptor) descriptor.writable = true;
    // 给原型上添加方法
    Object.defineProperty(target, descriptor.key, descriptor);
  }
}

function _createClass(Constructor, protoProps, staticProps) {
  // 将静态方法和属性添加到Person的Constructor
  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  if (staticProps) _defineProperties(Constructor, staticProps);
  Object.defineProperty(Constructor, "prototype", { writable: false });
  return Constructor;
}

// /*#__PURE__*/ 纯函数
// webppack 进行压缩tree-shaking 直接去除此段代码
var Person = /*#__PURE__*/ (function () {
  function Person(name) {
    // 这个方法检测this是不是new Person()创建出来的
    _classCallCheck(this, Person);

    this.name = name;
  }
  // 给Person原型上添加方法
  _createClass(Person, [
    {
      key: "eat",
      value: (function (_eat) {
        function eat() {
          return _eat.apply(this, arguments);
        }

        eat.toString = function () {
          return _eat.toString();
        };

        return eat;
      })(function () {
        console.log(eat);
      })
    }
  ]);

  return Person;
})();

ES6转ES5的继承代码

class Father {
  constructor(name, age) {
    this.name = name
    this.age = age
  }
  say() {
    console.log(this.name + ' say~');
  }
}
class Son extends Father {
  constructor(name, age, toy) {
    super(name, age)
    this.toy = toy
  }
  play(){
    console.log(this.name + ' play computer~')
  }
}

// babel转换后的代码
"use strict";

function _typeof(obj) {
  "@babel/helpers - typeof";
  return (
    (_typeof =
      "function" == typeof Symbol && "symbol" == typeof Symbol.iterator
        ? function (obj) {
            return typeof obj;
          }
        : function (obj) {
            return obj &&
              "function" == typeof Symbol &&
              obj.constructor === Symbol &&
              obj !== Symbol.prototype
              ? "symbol"
              : typeof obj;
          }),
    _typeof(obj)
  );
}

function _inherits(subClass, superClass) {
  if (typeof superClass !== "function" && superClass !== null) {
    throw new TypeError("Super expression must either be null or a function");
  }
  // 等价于自己实现的继承方法,直接在创建时设置默认值
  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: { value: subClass, writable: true, configurable: true }
  });
  Object.defineProperty(subClass, "prototype", { writable: false });
  // 静态方法的继承
  // 作用: Son.__proto__ 指向 Father.prototype
  if (superClass) _setPrototypeOf(subClass, superClass);
}

function _setPrototypeOf(o, p) {
  _setPrototypeOf =
    Object.setPrototypeOf ||
    function _setPrototypeOf(o, p) {
      o.__proto__ = p;
      return o;
    };
  return _setPrototypeOf(o, p);
}

function _createSuper(Derived) {
  var hasNativeReflectConstruct = _isNativeReflectConstruct();
  return function _createSuperInternal() {
    var Super = _getPrototypeOf(Derived),
      result;
    if (hasNativeReflectConstruct) {
      var NewTarget = _getPrototypeOf(this).constructor;
      // 简单理解: 创建NewTarget对象,内部执行Super函数的内容
      //                         Father  参数      Son
      result = Reflect.construct(Super, arguments, NewTarget);
    } else {
      result = Super.apply(this, arguments);
    }
    return _possibleConstructorReturn(this, result);
  };
}

function _possibleConstructorReturn(self, call) {
  if (call && (_typeof(call) === "object" || typeof call === "function")) {
    return call;
  } else if (call !== void 0) {
    throw new TypeError(
      "Derived constructors may only return object or undefined"
    );
  }
  return _assertThisInitialized(self);
}

function _assertThisInitialized(self) {
  if (self === void 0) {
    throw new ReferenceError(
      "this hasn't been initialised - super() hasn't been called"
    );
  }
  return self;
}

function _isNativeReflectConstruct() {
  if (typeof Reflect === "undefined" || !Reflect.construct) return false;
  if (Reflect.construct.sham) return false;
  if (typeof Proxy === "function") return true;
  try {
    Boolean.prototype.valueOf.call(
      Reflect.construct(Boolean, [], function () {})
    );
    return true;
  } catch (e) {
    return false;
  }
}

function _getPrototypeOf(o) {
  _getPrototypeOf = Object.setPrototypeOf
    ? Object.getPrototypeOf
    : function _getPrototypeOf(o) {
        return o.__proto__ || Object.getPrototypeOf(o);
      };
  return _getPrototypeOf(o);
}

function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

function _defineProperties(target, props) {
  for (var i = 0; i < props.length; i++) {
    var descriptor = props[i];
    descriptor.enumerable = descriptor.enumerable || false;
    descriptor.configurable = true;
    if ("value" in descriptor) descriptor.writable = true;
    Object.defineProperty(target, descriptor.key, descriptor);
  }
}

function _createClass(Constructor, protoProps, staticProps) {
  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  if (staticProps) _defineProperties(Constructor, staticProps);
  Object.defineProperty(Constructor, "prototype", { writable: false });
  return Constructor;
}

var Father = /*#__PURE__*/ (function () {
  function Father(name, age) {
    _classCallCheck(this, Father);

    this.name = name;
    this.age = age;
  }

  _createClass(Father, [
    {
      key: "say",
      value: function say() {
        console.log(this.name + " say~");
      }
    }
  ]);

  return Father;
})();

var Son = /*#__PURE__*/ (function (_Father) {
  // 继承原型(inheritPrototype()等价于自己写的继承方法)
  // Son.protype = Object.create(_Father.prototype)
  _inherits(Son, _Father);

  var _super = _createSuper(Son);

  function Son(name, age, toy) {
    var _this;

    _classCallCheck(this, Son);
    // 相当于 Son.call(this, name, age), 但限制用Son直接调用,必须用new
    // 所以用_createSuper创建一个新的函数进行调用Father的构造器
    _this = _super.call(this, name, age)
    // _this = { name: ; age: ; toy: ; }
    _this.toy = toy;
    return _this;
  }

  _createClass(Son, [
    {
      key: "play",
      value: function play() {
        console.log(this.name + " play computer~");
      }
    }
  ]);

  return Son;
})(Father);

创建类继承自内置类

// 默认类继承自Object

// 这种方式可以对系统类进行扩展
class Fhup extends Array { // Array构造器会根据给定的元素创建一个 JavaScript 数组
  firstItem() {
    console.log(this[0], this.at(2)) // at获取索引上的元素
  }
}
var f = new Fhup(333, 666, 999) // f就是一个数组
f.firstItem()

f.push('12321312')
console.log(f) // Fhup(4) [ 333, 666, 999, '12321312' ]

JS实现混入效果

// js支持: 单继承
class Top {

}

function MixinFn(baseClass) {
  class newClass extends baseClass{
    run() {
      console.log('run~~~');
    }
  }
  return newClass
}
// 直接返回匿名类,不需要写名字
function MixinFn2(baseClass) {
  return class extends baseClass{
    eat() {
      console.log('eat~~~');
    }
  }
}

// MixinFn2返回的新类, 又被传入MixinFn返回新的类(实现多继承)
// 不推荐使用, 了解就行
var newClass = MixinFn(MixinFn2(Top))
var nc = new newClass()
nc.eat()
nc.run()

传统面向对象多态 ts文件

// ts-node 运行ts代码
/**
 * 传统的面向对象的三个前提:
 * 1.必须有继承. (继承是多态的前提)
 * 2.必须有重写. (子类重写父类的方法)
 * 3.必须有父类引用指向子类对象 var shape = new Rectangle()
 */
class Shape {
  constructor() {}
  getArea() {}
}
class Rectangle extends Shape {
  x: number;
  y: number;
  constructor(x: number, y: number) {
    super();
    this.x = x;
    this.y = y;
  }
  getArea() {
    return this.x * this.y;
  }
}
class Circle extends Shape {
  r: number;
  constructor(r: number) {
    super();
    this.r = r;
  }
  getArea() {
    return this.r * 2 * Math.PI;
  }
}

// 多态: 对不同的数据类型执行同一个操作时,表现出来的行为(形态)不一样,就是多态的体现.
function calcArea(shape: Shape) {
  console.log(shape.getArea());
}

calcArea(new Circle(3));
calcArea(new Rectangle(3, 33));

export {};

JS面向对象多态

// JS多态不严格
function Fn(foo) {
  foo.say()
}

var obj = {
  name: 'Fhup',
  say: function() {
    console.log('456');
  }
}
class Person {
  say() {
    console.log('123');
  } 
}

Fn(obj)
var p = new Person()
Fn(p)