esprimaでとれるASTのnodeタイプについてメモ

ここ数日esprimaで遊んでる。
esprima.parse()estraverse.traverse() では、ASTを取得し、nodeのtypeで処理を分けるんだけど、やりたい事をやるのにどのnodeをチェックすればいいのかわからない。

例えば、コード中で var x = 1; とすべき所を x = 1; としてしまってグローバル変数が出来てしまうのを検出したい時に、 AssignmentExpression だけチェックすれば良いのか?となる。

nodeのtypeは esprima.Syntax で見れる。
また、あるnodeを取得したい時にどんなコードを書けばよいのかは、esprimaのfixture見ればわかる。

github.com

本当はEcmaScriptの仕様見た方が良いんだろうけど、すぐ読める気がしない。 なので、fixture見ながら、REPLでポチポチやって、各nodeの特徴をメモしていった。

(半分くらい書いて気づいたけど、ES6独自のnode以外はMDN見れば良いようだった……)
Parser API - Mozilla | MDN

↓↓↓↓↓メモ本文はこちらになります↓↓↓↓↓

Esprima Syntax メモ

↑↑↑↑↑メモ本文はこちらになります↑↑↑↑↑

メモる過程で気づいたこと

言語仕様を軽くおさらいする良い機会になった。
幾つか気づいた事があったのでメモ。

new する時にカッコ必要ない

コンストラクタが引数とらないとき、new A() のカッコを省略できる

> new Date();
Mon Jul 13 2015 11:31:55 GMT+0900 (JST)
> new Date;
Mon Jul 13 2015 11:31:56 GMT+0900 (JST)

generator の delegate ば便利

同期的にコードが書けるということで大好評のgeneratorですが、delegateって機能使うと更に便利という事がわかった。

[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function#Example_with_yield:title]

↑からコード抜粋

function* anotherGenerator(i) {
  yield i + 1;
  yield i + 2;
  yield i + 3;
}

function* generator(i){
  yield i;
  yield* anotherGenerator(i);
  yield i + 10;
}

var gen = generator(10);

console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20

まじか!!!!!!便利!!!!! !!!!!!

日本語の解説記事は無いみたいだった。
ちゃんと英語の情報チェックしなきゃ〜〜

{a:1} はObjectではない??

> esprima.parse('{a:1}').body[0]
{ type: 'BlockStatement',
  body: [ { type: 'LabeledStatement', label: [Object], body: [Object] } ] }

> esprima.parse('a = {a:1}').body[0]
{ type: 'ExpressionStatement',
  expression:
   { type: 'AssignmentExpression',
     operator: '=',
     left: { type: 'Identifier', name: 'a' },
     right: { type: 'ObjectExpression', properties: [Object] } } }

{a:1} とだけ書いた時はLabeledStatementと判断されてる。

ES6で new.target が追加される

ES6では全てのfunctionが new.target を持つようになる。
これによって、class Child extends Parent {}; new Child(); とした時に、Parentのコンストラクタ内でChildのコンストラクタを取得できるようになる、のかな?

http://www.2ality.com/2015/02/es6-classes-final.html#allocating_and_initializing_the_instance_object

うーんムズそう

LabeledStatement

ループにラベルをつけて、breakやcontinueで指定することで、ネストしたループを抜けたり出来る

a: while (1) {
  b: while (1) { 
    console.log('b'); 
    break a; 
  } 
  console.log('a'); 
}

// b

この機能ほぼ使わないからすぐ忘れてて、毎年3回くらい思い出しては驚いてる気がする