自らes 6のclassを手に入れる

7001 ワード

新世代の標準はすでにいくつかの日を提出して、最近reactを書く時、reactは大量のclassの文法を使ってコンポーネントを書いて、classに対する理解はあまり深くなくて、そこでここでbabelから変換したコードをみんなに分かち合います.

クラス=コンストラクション関数+プロトタイプ


Es 6標準のクラスは他の言語のクラスと似ていますが、これは文法糖にすぎません.底層はプロトタイプ継承によって実現されています.まず簡単なクラスの形式を見てみましょう.
 class A {
   constructor(){
     this.name='xiaoming'
   }
   sayHello(){
     console.log('hello')
   }
 }

コンストラクション関数とクラス内の関数を含み、プロトタイプ継承についてよく知っていれば、この形式は近似的に書くことができます.
function A(){
  this.name='xiaoming';
}
A.prototype={
  sayHello:function(){
    console.log('hello')
  }
}

これがクラスの雛形ですが、実際の操作は少し違います.次はbabel翻訳のes 5の文法です.
'use strict';

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; 
}}();

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

var A = function () {
  function A() {
    _classCallCheck(this, A);
    this.name = 'xiaoming';
  }

  _createClass(A, [{
    key: 'sayHello',
    value: function sayHello() {
      console.log('hello');
    }
  }]);

  return A;
}();

このコードに興味がある方はご覧ください.このクラスAは関数として呼び出すことができません.A()この方法で呼び出すとエラーが発生します.
let a = new A();

このように1つのクラスをインスタンス化して、もちろんクラスはすべて継承する必要があって、新しいバージョンの中で継承はextendsで実現して、このようなクラスBがクラスAを継承することを考慮します
 class A {
  constructor(){
    this.name='xiaoming'
  }
  sayHello(){
    console.log('hello')
  }
}
  class B extends A{
  constructor(){
    super() 
    this.age=12
  }
  sayHello(){
    console.log('hello')
  }
}

これは継承後のコードです
'use strict';

var _createClass = function () { 
function defineProperties(target, props) { 
...// 
 }();

function _possibleConstructorReturn(self, call) { if (!self) {
  throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } 
  return call && (typeof call === "object" || typeof call === "function") ? call : self; 
}

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, {
  constructor: {
    value: subClass, 
    enumerable: false,
    writable: true,
    configurable: true 
  }
 }); 
if (superClass) 
  Object.setPrototypeOf ?
  Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

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

var A = function () {
  function A() {
    _classCallCheck(this, A);

    this.name = 'xiaoming';
    this.say = function () {
      console.log("123");
    };
  }

  _createClass(A, [{
    key: 'sayHello',
    value: function sayHello() {
      console.log('hello');
    }
  }]);

  return A;
}();

var B = function (_A) {
  _inherits(B, _A);

  function B() {
    _classCallCheck(this, B);

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

    _this.age =12;
    return _this;
  }

  _createClass(B, [{
    key: 'sayHello',
    value: function sayHello() {
      console.log('hello');
    }
  }]);

  return B;
}(A);

コードが長いので、見る必要はありません.ただ見るだけです.inheritsという関数は、この文から
subClass.prototype = Object.create(superClass && superClass.prototype, {
  constructor: { 
    value: subClass, 
    enumerable: false, 
    writable: true, 
    configurable: true 
  }
});

ここでは、計算前がfalseの場合、後の式は計算されません.もちろん、falseまたは最後の値を返します.これは左から右に計算されます.superClassが存在する場合は、superClassを計算します.prototypeは、もちろん存在します.この文は、BのプロトタイプをAのprototypeをプロトタイプとするオブジェクト、つまり
B.prototype.__proto__=A.prototype

proto VS prototype


ここで__proto__という属性は、各オブジェクトに存在するため、オブジェクトはtoString()のような自分の属性や方法ではない多くの属性を継承することができる.toString()はこのオブジェクト自体の方法ではありませんが、1つのオブジェクトを呼び出すこの方法を呼び出すと、このオブジェクト自体がなく、このオブジェクトの__proto__を探しに行き、その__proto__が指すオブジェクトの中で探しに行き、見つからないと、この__proto____proto__の中で探し続け、これは原型チェーンを形成し、見つけるまで見つからないとエラーを報告します.prototype__proto__の違いは明らかで、prototypeは関数オブジェクト特有で、彼は1つの属性として別のオブジェクト、すなわちこの関数のプロトタイプオブジェクトを指して、その存在の目的はただオブジェクトを生産するためで、この関数newを通じて出てきたオブジェクトはすべて1つの__proto__の属性がこの関数のプロトタイプオブジェクトを指して、以下のコードから見ることができます
function A(){
  this.name='xiaoming'
}
A.prototype={
  sayhi:function(){
    console.log('hi')
  }
}
var a=new A();
console.log(a.__proto__===A.prototype)
// true

すなわち、オブジェクトの__proto__属性は、そのオブジェクトを製造するコンストラクション関数のプロトタイプオブジェクトを指し、オブジェクトの字面量形式で作成されたオブジェクトの__proto__Object.prototypeであり、
o = {};//  :
o = Object.create(Object.prototype);

では、これまでの話を続けてみると、_inherits関数にこの言葉があります.
if (superClass) 
Object.setPrototypeOf ? 
Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; 

このようなクラスの__proto__は親を指し,プロトタイプチェーンヘッダを親を指す,すなわちBではAのメソッドと属性を用いることができ,Bというコンストラクション関数内ではBのプロトタイプオブジェクトが以前のコードで説明されていることに注意し,Object.createの方法でBのプロトタイプオブジェクトをAのプロトタイプにバインドし,BのプロトタイプオブジェクトはプロトタイプチェーンプロトタイプによってAを用いるプロトタイプオブジェクトの属性と方法を継承することができる.とにかく最後の状況はこうだった
B.__proto__=A
B.prototype= xx
 xx:{
__proto__:A.prototype
constructor:B
...
}

newを使用してBのインスタンスbを作成すると、constructorでthisが得られる.xx、例えばthis.age this.age... など、Bのコンストラクション関数にsuper()があることを忘れてはいけません.そうしないと、Aのコンストラクション関数も実行されます.そうしないと、name属性がなく、そのオブジェクトの__proto__をそのオブジェクトxx、つまりBというコンストラクション関数のプロトタイプオブジェクトに指向し、このプロトタイプチェーン上の属性と方法にアクセスできます.

まとめ


新しいバージョンのクラスもプロトタイプ継承に基づいているので、基礎を築けば、新しいものに出会ってもよく理解できます.classのconstructorは以前のコンストラクション関数に対応しています.クラス全体の内容はこのコンストラクション関数のプロトタイプオブジェクトの内容です.継承に継承されたオブジェクトの内容があれば、クラス名xxで以前のコンストラクション関数を指すことができます.xx.prototypeは、プロトタイプオブジェクトを指す.新しい文法形式は、実装の詳細を外部に隠し、より簡潔に書き、不正な使用時のエラーヒントもあります.