JavaScript 五十问——从源码剖析 ES6 Class 的完成机制

Class是ES6中新到场的继续机制,现实是Javascript关于原型继续机制的语法糖,本质上是对原型继续的封装。本文将会议论:
1、ES6 class的完成细
2、相干Object API清点
3、Javascript中的继续完成计划清点

正文

1、Class 完成细节

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

    static type = 'being'

  sayName (){
    return this.name
    }

  static intro(){
    console.log("")
    }
}

class Men extends Person{
    constructor(name, age){
        super()
      this.gender = 'male'
    }
}

const men = new Men()

以上代码是ES6 class的基本运用体式格局,经由过程babel剖析后,重要代码组织以下:

'use strict';

var _createClass = function () {...}();// 给类增加要领

function _possibleConstructorReturn(self, call) { ...}//完成super

function _inherits(subClass, superClass) {...}// 完成继续

function _classCallCheck(instance, Constructor) {...} // 防备以函数的体式格局挪用class

var Person = function () {
  function Person(name, age) {
      _classCallCheck(this, Person);

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

  _createClass(Person, [{
      key: 'sayName',
      value: function sayName() {
        return this.name;
      }
  }], [{
      key: 'intro',
      value: function intro() {
        console.log("");
      }
  }]);

  return Person;
  }();

Person.type = 'being'; //静态变量

var Men = function (_Person) {
  _inherits(Men, _Person);

  function Men(name, age) {
    _classCallCheck(this, Men);

    var _this = _possibleConstructorReturn(this, (Men.__proto__ || Object.getPrototypeOf(Men)).call(this));

    _this.gender = 'male';
    return _this;
  }
    
  return Men;
  }(Person);

var men = new Men();

为何说es6的class 是基于原型继续的封装呢? 最先省略的四个函数又有什么作用呢?
下面,我们就从最最先的四个函数入手,细致的诠释es6的class 是怎样封装的。

第一:_classCallCheck函数, 磨练组织函数的挪用体式格局:
代码

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

我们晓得,在javascript中 person = new Person() ,一般完成以下几件事:
1、建立一个新的对象 Object.create()
2、将 新对象的 this 指向 组织函数的原型对象
3、新对象的__proto__ 指向 组织函数
4、实行组织函数
而一般函数挪用,this一般指向全局
因而,_classCallCheck函数是用来检测类的挪用体式格局。防备类的组织函数以一般函数的体式格局挪用。

第二: _createClass 给类增加要领

var _createClass = 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); 
        } 
    } 
    return function (Constructor, protoProps, staticProps) { 
        if (protoProps) defineProperties(Constructor.prototype, protoProps); //非静态函数 -> 原型
        if (staticProps) defineProperties(Constructor, staticProps); return Constructor; // 静态函数 -> 组织函数
    }; 
}();

_createClass是一个闭包+马上实行函数,以这类体式格局模仿一个作用域,将defineProperties私有化。
这个函数的重要作用是经由过程Object.defineProperty给类增加要领,其中将静态要领增加到组织函数上,将非静态的要领增加到组织函数的原型对象上。

第三: _inherits 完成继续

function _inherits(subClass, superClass) {
     if (typeof superClass !== "function" && superClass !== null) { 
         throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); 
        } 
    subClass.prototype = Object.create(superClass && superClass.prototype,  // 子类的原型的__proto__指向父类的原型
        //给子类增加 constructor属性 subclass.prototype.constructor === subclass
        { constructor: 
            { 
                value: subClass, 
                enumerable: false, 
                writable: true, 
                configurable: true 
            } 
        }
    ); 
    if (superClass) 
        //子类__proto__ 指向父类
        Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; 
}

从这个函数就能够很明显的看出来,class完成继续的机制了。

第四: _possibleConstructorReturn super()

function _possibleConstructorReturn(self, call) { 
    if (!self) { 
        throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); //保证子类组织函数中 显式挪用 super()
    } 
    return call && (typeof call === "object" || typeof call === "function") ? call : self; 
}

要想明白这个函数的作用,须要连系他的挪用场景

var _this = _possibleConstructorReturn(this, (Men.__proto__ || Object.getPrototypeOf(Men)).call(this));// function Men(){}

此时已实行完_inherits函数,Men.__proto__ === Person
相当于:

var _this = _possibleConstructorReturn(this, Person.call(this));

很明显,就是将子类的this 指向父类。

API 总结

依据以上的剖析,es6 class 的完成机制也能够总结出来了:
毫无疑问的,class机制照样在prototype的基本之上举行封装的
——contructor 实行组织函数相干赋值
——运用 Object.defineProperty()要领 将要领增加的组织函数的原型上或组织函数上
——运用 Object.create() 和 Object.setPrototypeOf 完成类之间的继续 子类原型__proto__指向父类原型 子类组织函数__proto__指向父类组织函数
——经由过程变动子类的this 作用域完成super()

清点JavaScript中的继续体式格局

1.原型链继续
2.组织函数继续
3.组合继续
4.ES6 extends 继续

细致内容能够参考 聊一聊 JavaScript的继续体式格局https://segmentfault.com/a/11…

跋文

终究写完了,在没有收集辅佐的情况下写博客真是太难了!绝知此事要躬行呀!
本来以为写一篇关于class的博客还不简朴吗,就是原型链继续那一套呗,如今总结下来,照样有许多处所须要注重的;进修到了许多!嗯 不说了, 我另有好几个坑要填呢~
假如这篇文章对你有协助的话,迎接点赞珍藏!
假如你有疑问的话,愿望主动留言,配合议论,配合进步!

参考文档

ES6—类的完成道理 https://segmentfault.com/a/11…

JavaScript 红宝书

    原文作者:蔺相如如
    原文地址: https://segmentfault.com/a/1190000017842257
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞