ES6的class和ES6的class和继承转化为ES5的源码阅

2022-05-02  本文已影响0人  咸鱼不咸_123

1.认识class定义类

我们会发现,按照前面的构造函数形式创建类,不仅仅和编写普通的函数过于相似,而且代码并不容易理解。

1.1 类的定义和类的特性

类的定义的两种方式:

// * 类的声明
class Person{

}

// * 类的表达式
var Animal=class{

}

类的特性:

// * 研究类的特点
console.log(Person.prototype);//{}
console.log(Person.prototype.__proto__);//[Object: null prototype] {}
console.log(Person.prototype.constructor); //[class Person]

console.log(typeof Person);//function
// typeof只会打印固定的几个
var p=new Person();
console.log(p.__proto__);//{}
console.log(p.__proto__==Person.prototype); //true

// * class是之前es5实现的语法糖形式而已
// function Person2(){}
// console.log(Person2.prototype.constructor);//[Function: Person2]
// // * 声明一个函数
// function fpp(){

// }

// // * 函数表达式
// var foo=function(){

// }

1.2 类的构造函数

如果我们希望在创建对象的时候给类传递一些参数,这个时候应该如何做呢?

当我们通过new关键字操作类的时候,会调用这个constructor函数,并且执行如下操作:

  1. 在内存中创建一个新的对象(空对象)
  2. 在这个对象内部的[[prototype]]属性会被赋值为该类的prototype属性
  3. 构造函数内部的this指向这个创建出来的新对象
  4. 执行构造函数内部的代码
  5. 如果构造函数没有返回其他非空对象,则返回创建出来的新对象
// * 类的声明
class Person{
  // * 类的构造方法 通过new关键字创建一个对象时,会调用这个构造方法
  // * 一个类只有一个构造方法
  // * 通过new关键字会执行如下几个步骤:
  // * 1 在内存中创建一个新的对象(空对象)
  // * 2 将这个新对象的__proto__执行类的prototype
  // * 3 将构造方法的this指向 这个新创建的对象
  // * 4 执行构造函数内部的代码
  // * 5 如果构造函数没有其他的返回对象,会将这个新对象返回
  constructor(name,age){
    this.name=name;
    this.age=age;
  }

}
var p=new Person("wjy",20);
console.log(p);//Person { name: 'wjy', age: 20 }

1.3 类的实例方法、访问器方法、静态方法

var names=["abc","efg","zs","ls","ww"]
class Person{
  constructor(name,age){
    this.name=name;
    this.age=age;
    this._address="怀化"
  }
  // * eating和running是实例方法,只能通过对象.方法名才能访问
  eating(){
    console.log(this.name+"在吃东西");
  }
  running(){
    console.log(this.name+"在跑步");
  }

  // * 类的访问方法
  get address(){
    return this._address;
  }
  set address(value){
    this._address=value
  }

  // * 类的静态方法(类名)  可以通过类名进行访问 也可以通过对象来访问
  static randomPerson(){
    // * Math.floor 向下取整 
    var nameIndex=Math.floor(Math.random()*names.length)
    var name=names[nameIndex];
    var age=Math.floor(Math.floor(Math.random()*100))//*  向下取整0-100但不包含100  向上取值就不会包含 0了 1-100
    return new Person(name,age);
  }
}
var p=new Person("wjy",20)
console.log(p);
// * 判断类定义的方法是每个实例对象都会创建一份,还是共享一份
p.eating();
p.running();

var p2=new Person("hyz",21)
// * 打印出现发现都是true,所以类定义的方法是共享的,不是每个实例对象内部会创建一份
console.log(p.eating==p2.eating);//true
console.log(p.running==p2.running);//true
console.log(p.eating==Person.prototype.eating);
console.log(Object.getOwnPropertyDescriptors(Person.prototype));

console.log(p.address);//怀化
p.address="北京"
console.log(p.address);//北京

for(var i=0;i<50;i++){
  console.log(Person.randomPerson());
}

1.4 ES6类的继承 -extends

前面我们花了很大的篇幅讨论了在ES5中实现继承的方案,虽然最终实现了相对满意的继承机制,但是过程却依然非常繁琐的

class Person{
  constructor(name,age){
    this.name=name;
    this.age=age;
  }
}

class Student extends Person{ //* 实现了 Student 继承了Person
   constructor(name,age,sno){
    // * 怎么将父类的属性继承过来呢
    super(name,age);
    this.sno=sno;
  }
}
1.4.1 super关键字

我们会发现在上面的代码中我使用了一个super关键字,这个super关键字有不同的使用方式:

请注意看下面的:如果我不用父类的构造函数,在子类直接绑定在自己属性上,但是在创建实例对象的时候会报错

class Person{
  constructor(name,age){
    this.name=name;
    this.age=age;
  }
}

class Student extends Person{ //* 实现了 Student 继承了Person
  constructor(name,age,sno){
    this.name=name;
    this.age=age;
    this.sno=sno;
  }
}
var stu=new Student("wjy",20,1)
43.png
1.4.1 super的两种用法
  1. 调用父类的构造方法

    • super()
  2. 调用父类的实例方法

    • super.方法名(参数)
  3. 调用父类的静态方法

    • super.方法名(参数)

可以重写父类的方法也可以在重写的过程中,对父类代码的复用,通过使用super关键字来实现的。

class Person{
  constructor(name,age){
    this.name=name;
    this.age=age;
  }
  running(){
    console.log(this.name+"在跑步");
  }
  eating(){
    console.log(this.name+"在吃东西");
  }
  personMethod(){
    console.log("处理逻辑1");
    console.log("处理逻辑2");
    console.log("处理逻辑3");
  }

  static staticMethod(){
    console.log("PersonStaticMethod");
  }
}

class Student extends Person{ //* 实现了 Student 继承了Person
  constructor(name,age,sno){
   super(name,age);
   this.sno=sno;
  }
  studying(){
    console.log(this.name+"在学习");
  }
  // *  子类对父类方法的重写
  running(){
    console.log("student "+this.name+"在跑步");
  }
  // * 重写personMethod,并父类实例方法的代码逻辑
  personMethod(){
    super.personMethod()
    // console.log("处理逻辑1");
    // console.log("处理逻辑2");
    // console.log("处理逻辑3");
    console.log("处理逻辑4");
    console.log("处理逻辑5");
    console.log("处理逻辑6");
  }
  // * 重写父类静态方法,也可以复用静态方法的代码逻辑
  static staticMethod(){
    console.log("studentStaticMethod");
  }
 
}
var stu=new Student("wjy",20,1)
console.log(stu);
stu.eating()
stu.running()
console.log(Object.getOwnPropertyDescriptors(stu.__proto__));//* Student原型上没有eating和running方法
stu.personMethod()
Student.PersonStaticMethod()
44.png

2.es6转es5代码分析

babel官网:https://babeljs.io/

2.1 ES6的class转ES5的源码阅读

class Person{
    constructor(name,age){
      this.name=name;
      this.age=age;
    }
    eating(){
      console.log(this.name+"在吃东西");
    }
    running(){
      console.log(this.name+"在跑步");
    }
}
// * 一些浏览器对es6的语法不支持,不能正确的识别

"use strict";


function _classCallCheck(instance, Constructor) {
  // 判断这个构造哈函数的prototype是否在实例对象的原型链上
  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;
}

// * 使用的是立即执行函数
//  /*#__PURE__*/ 纯函数:没有副作用,webpack进行压缩的时候,会涉及到tree-shaking:将一些从来没有用到的代码会删掉
var Person = /*#__PURE__*/ (function () {
  // * 定义了一个Person的构造函数
  function Person(name, age) {  
    // 判断这个this是不是通过new关键字进行调用的
    _classCallCheck(this, Person);

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

  _createClass(Person, [
    {
      key: "eating",
      value: function eating() {
        console.log(this.name + "在吃东西");
      }
    },
    {
      key: "running",
      value: function running() {
        console.log(this.name + "在跑步");
      }
    }
  ]);

  return Person;
})();

2.2 ES6的继承转ES5的源码阅读

class Person{
  constructor(name,age){
    this.name=name;
    this.age=age;
  }
  running(){
    console.log(this.name+"在跑步。");
  }
}

class Student extends Person{
  constructor(name,age,sno) {
    super(name,age);
    this.sno=sno;
  }
  studying(){
    console.log(this.name+"在学习");
  }
}

// * 转es5的代码
"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) {
  // * 判断传递superClass是否为function或者为null
  if (typeof superClass !== "function" && superClass !== null) {
    throw new TypeError("Super expression must either be null or a function");
  }
  // * 将子类的原型对象指向 对象(这个对象的__proto__指向的是父类的prototype)
  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: { value: subClass, writable: true, configurable: true }
  });
  Object.defineProperty(subClass, "prototype", { writable: false });
  // * 这个是为了让静态方法的继承
  if (superClass) _setPrototypeOf(subClass, superClass);
}
// * 设置子类的__proto__指向父类
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;
      // Super:Person
      // arguments:参数
      // NewTarget:Student
      // 会通过Super创建出来一个实例,这个实例的原型constructor指向的是NewTarget
      // 会通过Person创建一个实例,这个实例的原型指向的是 Person
      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;
  }
}
// * 获取对象的__proto__属性
function _getPrototypeOf(o) {
  _getPrototypeOf = Object.setPrototypeOf
    ? Object.getPrototypeOf
    : function _getPrototypeOf(o) {
        return o.__proto__ || Object.getPrototypeOf(o);
      };
  return _getPrototypeOf(o);
}

// * 判断是否是通过new关键字来调用类
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;
}

// * Person的立即执行函数
var Person = /*#__PURE__*/ (function () {
  function Person(name, age) {
    _classCallCheck(this, Person);

    this.name = name;
    this.age = age;
  }
// * 在这里将类的实例方法、静态方法分别定义到类的原型对象上和类上
  _createClass(Person, [
    {
      key: "running",
      value: function running() {
        console.log(this.name + "在跑步。");
      }
    }
  ]);

  return Person;
})();

// * 立即执行函数
var Student = /*#__PURE__*/ (function (_Person) {

  // * 将构造函数Student的原型对象指向 一个对象(这个对象的__proto指向的是Person.prototype)
  // * 方法和之前的寄生组合式继承一样
  _inherits(Student, _Person);
// * 去拿到_super这个函数,因为Person不能直接当成一个函数来调用,它在这个函数中创建一个新的函数了
  var _super = _createSuper(Student);

  function Student(name, age, sno) {
    var _this;

    _classCallCheck(this, Student);

    _this = _super.call(this, name, age);
    _this.sno = sno;
    return _this;
  }

  _createClass(Student, [
    {
      key: "studying",
      value: function studying() {
        console.log(this.name + "在学习");
      }
    }
  ]);

  return Student;
})(Person);

3.总结

认识类和es6转es5的源码阅读.png
上一篇 下一篇

猜你喜欢

热点阅读