自制前段框架Day11.方括號(hào)讀取對(duì)象屬性

回顧思路

昨天把思路縷了一下官册。假設(shè)這樣編譯這樣一個(gè)字符串parse('user.student.name'),那首先就是期望傳入的scope對(duì)象有一個(gè)user屬性豁遭。user屬性有一個(gè)student屬性。student屬性有一個(gè)name屬性囚聚。事實(shí)上操作起來(lái)也是這樣一個(gè)流程:

  1. 先取scope.user屬性靖榕。
  2. 再取scope.user.student屬性。
  3. 再取scope.user.student.name屬性顽铸。

再看一下生成的tokens茁计。這tokens很簡(jiǎn)單,就是五個(gè):user, . ,student ,.,name谓松。
面對(duì)這些tokens的時(shí)候星压,AST的編譯過(guò)程是這樣:

  1. 生成program践剂。
  2. 進(jìn)入primary。
  3. 遇到的userToken是identifier類型娜膘,生成identifier節(jié)點(diǎn){type:ASTBuilder.Identifier,name:'user'},同時(shí)userToken被消耗掉逊脯。
  4. 遇到.token,產(chǎn)生子節(jié)點(diǎn)竣贪,同時(shí)把剛才的userToken生成的identifier節(jié)點(diǎn)設(shè)置為子節(jié)點(diǎn)的object军洼。
  5. 設(shè)置完object以后去查找下一個(gè)token,把查到的token設(shè)置為子節(jié)點(diǎn)的property演怎,也就是studentToken匕争。
  6. 形成了新的AST
  type:ASTBuilder.MemberExpression,
  object:{
      type:ASTBuilder.Identifier,
      name:'user'
    },
  property:{
    type:ASTBuilder.Identifier,
    name:'student'
    }
}

7 . studentToken被消耗,下一個(gè)又遇到了.token爷耀。再次產(chǎn)生子節(jié)點(diǎn)甘桑。每個(gè)子節(jié)點(diǎn)都有object屬性和property屬性。然后把剛才的AST設(shè)置為新AST的object歹叮,把下一個(gè)nameToken設(shè)置為新AST的property扇住。

8.AST構(gòu)建完成。

編譯這個(gè)AST邏輯稍微有點(diǎn)深盗胀,需要好好總結(jié)一下思路艘蹋。

  1. 首先要取到scope.user。這時(shí)候就要去挖到最深的節(jié)點(diǎn)票灰。最深的節(jié)點(diǎn)肯定是一個(gè)Ident類型的節(jié)點(diǎn)女阀,將傳入的scope和節(jié)點(diǎn)的name屬性加在一起,賦給一個(gè)變量屑迂,返回這個(gè)變量浸策。就是scope.user賦給一個(gè)變量,返回這個(gè)變量惹盼。所以這里需要?jiǎng)?chuàng)建一個(gè)變量庸汗,假設(shè)為變量v

  2. 拿到變量v以后,返回到解析子節(jié)點(diǎn)部分手报,這個(gè)v就是一個(gè)object蚯舱,將它和property結(jié)合,再賦值給一個(gè)變量掩蛤,也就是說(shuō)v.student賦值給一個(gè)變量枉昏,假設(shè)是v1。返回v1揍鸟。

  3. 拿到v1兄裂,函數(shù)棧還是在子節(jié)點(diǎn)部分,現(xiàn)在是最外層的,把v1和name結(jié)合晰奖,賦值給一個(gè)變量谈撒,假設(shè)是v2.返回v2。

  4. 綜上所述匾南,事實(shí)上在編譯子節(jié)點(diǎn)和identifier類型的節(jié)點(diǎn)時(shí)候港华,都需要產(chǎn)生變量,無(wú)非是進(jìn)入函數(shù)就產(chǎn)生變量午衰,還是拿到值以后在產(chǎn)生變量。

正題開始了

其實(shí)前幾天雖然沒(méi)發(fā)文章冒萄,但是還是做了一些工作的臊岸,寫了一些簡(jiǎn)單的代碼,這部分先跳過(guò)尊流,以后再補(bǔ)帅戒。
總之想要編譯這樣的代碼

it('方括號(hào)找屬性', function() {
    var fn = parse('student["name"]');
    expect(fn({student:{name:'wangji'}})).toBe('wangji');
  });

之前是遇到.這個(gè)token的時(shí)候產(chǎn)生子節(jié)點(diǎn),現(xiàn)在還要加上崖技,遇到[這個(gè)token也應(yīng)該產(chǎn)生子節(jié)點(diǎn)逻住。為了實(shí)現(xiàn)這個(gè)目標(biāo),先把peek和expect方法改造一下:

ASTBuilder.prototype.peek = function (e1,e2,e3,e4) {
  if (this.tokens.length > 0) {
   var text = this.tokens[0].text;
   if(text===e1||text===e2||text===e3||text===e4||(!e1&&!e2&&!e3&&!e4)){
     return this.tokens[0];
   }
  }
}
ASTBuilder.prototype.expect = function (e1,e2,e3,e4) {
  var token = this.peek(e1,e2,e3,e4);
  if(token){
    return this.tokens.shift();
  }
}

然后修改代碼

ASTBuilder.prototype.primary = function () {
  var primary;
  if (ASTBuilder.Constants.hasOwnProperty(this.tokens[0].text)) {
    primary = ASTBuilder.Constants[this.consume().text];
  } else if (this.expect("[")) {
    primary = this.arrayDeclaration();
  } else if (this.expect("{")) {
    primary = this.object()
  } else if (this.peek().identifier) {
    primary = this.identifier()
  } else {
    primary = this.constant();
  }
  var next;
  while ((next = this.expect('.', '['))) {
    if (next.text === "[") {
      primary = {
        type: ASTBuilder.MemberExpression,
        object: primary,
        property: this.primary(),
        computed:true
      }
      this.consume(']');
    } else {
      primary = {
        type: ASTBuilder.MemberExpression,
        object: primary,
        property: this.identifier(),
        computed:false
      }
    }

  }
  return primary;
}

現(xiàn)在腦補(bǔ)一下整個(gè)過(guò)程迎献,'student["name"]'這個(gè)被分成若干個(gè)token瞎访,student,[,name,],其實(shí)在生成token的時(shí)候吁恍,這個(gè)name就被解析成了constant類型的token扒秸。所以在后面生成AST的時(shí)候,如果發(fā)現(xiàn)是[這種token就把下一個(gè)token從primary流程走一遍冀瓦,因?yàn)橛锌赡苁莄onstant也有可能是identifier伴奥。(student['name']或者student[name]).
這樣一來(lái),成功生成AST翼闽。進(jìn)入compile階段拾徙。
目前的compile階段,右值的產(chǎn)生是通過(guò)identifier流程感局,因?yàn)橛命c(diǎn)分割的右值都是確定的identifier尼啡。可是用方括號(hào)分割的就不確定了询微,就像剛才說(shuō)的玄叠,有可能是constant,有可能是iden拓提。所以還要寫一個(gè)ifelse读恃。

  case ASTBuilder.MemberExpression:
      intoId = this.nextId();
      var left = this.recurse(ast.object);
      if(ast.computed){
        var right = this.recurse(ast.property);
        this.if_(left,this.assign(intoId,this.nonComputedMember(left,right)));
      }else{
        this.if_(left, this.assign(intoId, this.nonComputedMember(left, ast.property.name)))
      }
      return intoId;

之前的nonComputedMember方法已經(jīng)不夠了,需要一個(gè)computedMember方法:

Compiler.prototype.computedMember=function(left,right){
  return '('+left+')'+'['+right+']';
}

編譯成功。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末寺惫,一起剝皮案震驚了整個(gè)濱河市疹吃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌西雀,老刑警劉巖萨驶,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異艇肴,居然都是意外死亡腔呜,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門再悼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)核畴,“玉大人,你說(shuō)我怎么就攤上這事冲九“荩” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵莺奸,是天一觀的道長(zhǎng)丑孩。 經(jīng)常有香客問(wèn)我,道長(zhǎng)灭贷,這世上最難降的妖魔是什么温学? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮甚疟,結(jié)果婚禮上枫浙,老公的妹妹穿的比我還像新娘。我一直安慰自己古拴,他們只是感情好箩帚,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著黄痪,像睡著了一般紧帕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上桅打,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天是嗜,我揣著相機(jī)與錄音,去河邊找鬼挺尾。 笑死鹅搪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的遭铺。 我是一名探鬼主播丽柿,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼恢准,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了甫题?” 一聲冷哼從身側(cè)響起馁筐,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎坠非,沒(méi)想到半個(gè)月后敏沉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡炎码,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年盟迟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片潦闲。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡攒菠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出矫钓,到底是詐尸還是另有隱情,我是刑警寧澤舍杜,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布新娜,位于F島的核電站,受9級(jí)特大地震影響既绩,放射性物質(zhì)發(fā)生泄漏概龄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一饲握、第九天 我趴在偏房一處隱蔽的房頂上張望私杜。 院中可真熱鬧,春花似錦救欧、人聲如沸衰粹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)铝耻。三九已至,卻和暖如春蹬刷,著一層夾襖步出監(jiān)牢的瞬間瓢捉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工办成, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留泡态,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓迂卢,卻偏偏與公主長(zhǎng)得像某弦,于是被迫代替她去往敵國(guó)和親桐汤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

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