親自上手es6的class

新一代標(biāo)準(zhǔn)已經(jīng)提出有些日子了轮听,最近在寫(xiě)react的時(shí)候剥哑,react用了大量的class的語(yǔ)法去寫(xiě)組件别垮,對(duì)于class的理解不是很深刻盗舰,于是這里把從babel轉(zhuǎn)換的代碼分享給大家晶府。

類=構(gòu)造函數(shù)+原型

es6標(biāo)準(zhǔn)的類和其他語(yǔ)言的類很相似,但是這只是一種語(yǔ)法糖钻趋,底層還是通過(guò)原型繼承實(shí)現(xiàn)的川陆,首先看一個(gè)簡(jiǎn)單的類的形式

 class A {
   constructor(){
     this.name='xiaoming'
   }
   sayHello(){
     console.log('hello')
   }
 }

包含一個(gè)構(gòu)造函數(shù),和一個(gè)類里面的函數(shù)蛮位,如果大家對(duì)原型繼承有所了解的話较沪,這種形式可以近似寫(xiě)成

function A(){
  this.name='xiaoming';
}
A.prototype={
  sayHello:function(){
    console.log('hello')
  }
}

這就是類的雛形,但是實(shí)際操作上還是有些不同的失仁,下面就是babel翻譯的es5的語(yǔ)法

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

這個(gè)代碼感興趣大家可以看看尸曼,其中有幾個(gè)地方需要注意,這個(gè)類A不能當(dāng)成函數(shù)去調(diào)用萄焦,A()這種方法調(diào)用會(huì)報(bào)錯(cuò)控轿,可以

let a = new A();

這樣去實(shí)例化一個(gè)類,當(dāng)然類都是需要繼承的拂封,新版本中繼承用extends來(lái)實(shí)現(xiàn)茬射,考慮這樣一個(gè)類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);

代碼很長(zhǎng),都不用看,只看_inherits這個(gè)函數(shù)冒签,從這一句

subClass.prototype = Object.create(superClass && superClass.prototype, {
  constructor: { 
    value: subClass, 
    enumerable: false, 
    writable: true, 
    configurable: true 
  }
});

這里有個(gè)小技巧在抛,&&當(dāng)計(jì)算前面為false時(shí),就不計(jì)算后面的表達(dá)式了萧恕,當(dāng)然返回的是false或者最后一個(gè)值刚梭,這是從左向右計(jì)算的肠阱,這里意思就是如果 superClass 存在,那就計(jì)算 superClass.prototype朴读,當(dāng)然也就是存在的屹徘,這一句就是將B的原型設(shè)為一個(gè)以 A 的 prototype 為原型的對(duì)象,也就是說(shuō)

B.prototype.__proto__=A.prototype

proto VS prototype

這里__proto__這個(gè)屬性是每個(gè)對(duì)象都有的磨德,就是因?yàn)檫@個(gè)屬性的存在缘回,對(duì)象可以繼承很多不是他自己的屬性或方法,比如toString()典挑。雖然toString()不是這個(gè)對(duì)象自己的方法,但是去調(diào)用一個(gè)對(duì)象的這個(gè)方法時(shí)啦吧,這個(gè)對(duì)象自己沒(méi)有您觉,就會(huì)去找這個(gè)對(duì)象的__proto__,在它的__proto__所指向的對(duì)象中去找授滓,如果找不到琳水,就會(huì)繼續(xù)去在這個(gè)__proto____proto__中去找,這就形成了一個(gè)原型鏈般堆,直到找到為止在孝,找不到就會(huì)報(bào)錯(cuò)。
prototype__proto__之間的區(qū)別很明顯淮摔,prototype是函數(shù)對(duì)象所特有的私沮,他作為一個(gè)屬性指向另一個(gè)對(duì)象,即這個(gè)函數(shù)的原型對(duì)象和橙,它存在的目的只是為了生產(chǎn)對(duì)象仔燕,通過(guò)這個(gè)函數(shù)new出來(lái)的對(duì)象都有一個(gè)__proto__屬性指向這個(gè)函數(shù)的原型對(duì)象,從下面代碼就可以看出來(lái)

function A(){
  this.name='xiaoming'
}
A.prototype={
  sayhi:function(){
    console.log('hi')
  }
}
var a=new A();
console.log(a.__proto__===A.prototype)
// true

也就是說(shuō)魔招,對(duì)象的__proto__屬性指向那個(gè)制造這個(gè)對(duì)象的構(gòu)造函數(shù)的原型對(duì)象晰搀,通過(guò)對(duì)象字面量形式創(chuàng)建的對(duì)象的__proto__就是Object.prototype,

o = {};// 以字面量方式創(chuàng)建的空對(duì)象就相當(dāng)于:
o = Object.create(Object.prototype);

那么繼續(xù)之前的話題,_inherits函數(shù)中有這一句

if (superClass) 
Object.setPrototypeOf ? 
Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; 

這樣子類的__proto__就指向了父類办斑,就將原型鏈頭指向了父類外恕,也就是在B中可以使用A的方法和屬性,注意是在B這個(gè)構(gòu)造函數(shù)內(nèi)乡翅,B的原型對(duì)象在之前的代碼已經(jīng)解釋了鳞疲,通過(guò)Object.create方法把B的原型對(duì)象綁定到了A的原型上,B的原型對(duì)象可以通過(guò)原型鏈原型繼承使用A的原型對(duì)象的屬性和方法峦朗。
總之最后的情況是這樣的

B.__proto__=A
B.prototype=對(duì)象xx
對(duì)象xx:{
__proto__:A.prototype
constructor:B
...
}

當(dāng)使用new去創(chuàng)建一個(gè)B的實(shí)例b時(shí)會(huì)發(fā)生這樣的過(guò)程
在constructor中會(huì)得到以this.xx建丧,比如this.age this.age...
等等還有一個(gè)不能忘了在B的構(gòu)造函數(shù)中會(huì)有個(gè)super(),這樣A的構(gòu)造函數(shù)也會(huì)執(zhí)行了波势,不然沒(méi)有name屬性
然后就是將這個(gè)對(duì)象的__proto__指向那個(gè)對(duì)象xx翎朱,也就是B這個(gè)構(gòu)造函數(shù)的原型對(duì)象橄维,這樣就能訪問(wèn)這個(gè)原型鏈上的屬性和方法了。

總結(jié)

新版本的類也是基于原型繼承的拴曲,所以只要把基礎(chǔ)打好了争舞,遇到新的東西也理解的比較清楚,class中constructor對(duì)應(yīng)的還是以前的構(gòu)造函數(shù)澈灼,整個(gè)類里面的內(nèi)容就是這個(gè)構(gòu)造函數(shù)的原型對(duì)象的內(nèi)容竞川,如果有繼承還要加上繼承的對(duì)象的內(nèi)容,我們依然可以用類名xx來(lái)指代以前的構(gòu)造函數(shù)叁熔,xx.prototype來(lái)指代原型對(duì)象委乌。新的語(yǔ)法形式,對(duì)外隱藏了實(shí)現(xiàn)的細(xì)節(jié)荣回,寫(xiě)起來(lái)更加簡(jiǎn)潔遭贸,還有會(huì)在不正當(dāng)時(shí)使用時(shí)的錯(cuò)誤提示。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末心软,一起剝皮案震驚了整個(gè)濱河市壕吹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌删铃,老刑警劉巖耳贬,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異猎唁,居然都是意外死亡咒劲,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)胖秒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)缎患,“玉大人,你說(shuō)我怎么就攤上這事阎肝〖酚妫” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵风题,是天一觀的道長(zhǎng)判导。 經(jīng)常有香客問(wèn)我,道長(zhǎng)沛硅,這世上最難降的妖魔是什么眼刃? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮摇肌,結(jié)果婚禮上擂红,老公的妹妹穿的比我還像新娘。我一直安慰自己围小,他們只是感情好昵骤,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布树碱。 她就那樣靜靜地躺著,像睡著了一般变秦。 火紅的嫁衣襯著肌膚如雪成榜。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,268評(píng)論 1 309
  • 那天蹦玫,我揣著相機(jī)與錄音赎婚,去河邊找鬼。 笑死樱溉,一個(gè)胖子當(dāng)著我的面吹牛挣输,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播饺窿,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼歧焦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了肚医?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤向瓷,失蹤者是張志新(化名)和其女友劉穎肠套,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體猖任,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡你稚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了朱躺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刁赖。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖长搀,靈堂內(nèi)的尸體忽然破棺而出宇弛,到底是詐尸還是另有隱情,我是刑警寧澤源请,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布枪芒,位于F島的核電站,受9級(jí)特大地震影響谁尸,放射性物質(zhì)發(fā)生泄漏舅踪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一良蛮、第九天 我趴在偏房一處隱蔽的房頂上張望抽碌。 院中可真熱鬧,春花似錦决瞳、人聲如沸货徙。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)破婆。三九已至涮总,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間祷舀,已是汗流浹背瀑梗。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留裳扯,地道東北人抛丽。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像饰豺,于是被迫代替她去往敵國(guó)和親亿鲜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • class的基本用法 概述 JavaScript語(yǔ)言的傳統(tǒng)方法是通過(guò)構(gòu)造函數(shù)冤吨,定義并生成新對(duì)象蒿柳。下面是一個(gè)例子: ...
    呼呼哥閱讀 4,102評(píng)論 3 11
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券漩蟆,享受所有官網(wǎng)優(yōu)惠垒探,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 3,002評(píng)論 4 14
  • 特別說(shuō)明,為便于查閱怠李,文章轉(zhuǎn)自https://github.com/getify/You-Dont-Know-JS...
    殺破狼real閱讀 1,140評(píng)論 0 4
  • 在JavaScript中圾叼,原型鏈作為一個(gè)基礎(chǔ),老生長(zhǎng)談捺癞,今天我們就來(lái)深入的解讀一下原型鏈夷蚊。 本章主要講的是下面幾點(diǎn)...
    Devinnn閱讀 1,405評(píng)論 1 6
  • 大概有四年了,連暗戀都沒(méi)有過(guò)髓介,愛(ài)情匱乏得像一片荒蕪的沙漠惕鼓。但是最近,最近好像喜歡上了一個(gè)人版保,想起他呜笑,嘴角就不自覺(jué)上...
    淳安閱讀 241評(píng)論 0 1