さぁ、いよいよ前回説明した、エントリ関数を編集して、希望のNCデータ構成にしてみようか・・・と思っていましたが、トレーニングガイドを眺めて見るとポストプロセッサとのやりとりや、NCデータの出力書式などを定義している、グローバルセクションは少し理解しておいた方がよさそうです。
その前に、JavaScript言語の変数についても、少し詳しく調べてみました。
偶然、変数宣言で、Fusion360ポストと一般的なJavaScript言語との違いも見つかったので、報告しています。
変数の寿命・スコープ(影響範囲)
プログラミング言語では、まず変数を定義するところから始まりますが、その変数の寿命を意識していないと、エラーになるならまだいいですが、違う結果を吐き出されてしまう可能性もあります。
変数は大きく分けると、「グローバル変数」と「ローカル変数」に分類され、その寿命(スコープ)は「グローバルスコープ」「ローカルスコープ」となります
さらにC言語ではあまり気にした事なかったですが、JavaScriptの「ローカルスコープ」は「関数スコープ」と「ブロックスコープ」の違いも気にした方がいいようです。
この違いは、後述する「var」と「let」の違いの一つでもあるようです。
「参考サイト」
グローバルスコープとローカルスコープ
Fusion360のポストは、イベント処理的に対象の関数を呼び出します。
例えば、ポスト処理開始時には、「onOpen( )」関数が呼ばれ、定義された操作ごとに「onSection( )」が呼ばれます。
工具経路処理で、直線補間の動作では、「onLinear( )」、円弧補間時には「onCircular( )」が呼ばれます。
こんな感じで、処理する内容によりイベント的に関数が呼ばれポスト処理されていきます。
変数は各関数内部で宣言される場合と、関数の外側で宣言される場合があります。
関数の外側で宣言された変数はグローバル変数と呼ばれ、プログラム内のどの関数からでも参照でき、プログラムが終了するまで生き残ります。
これをグローバルスコープと呼びます。
どこからでも参照できるため、グローバル上では変数の宣言は重複出来ないほうが安全ですが、Fusion360では同じ名前で宣言できてしまうので、注意が必要です。
関数内部や、さらにその内部のブロック内部で宣言された変数は、ローカル変数と呼ばれ、その関数やブロック内部からしか参照できません。
したがって、違う関数やブロックでは同じ名前の変数を使用してもお互いに影響を与えません。さらにグローバル変数と同じ名前でもグローバル変数に影響をあたえません。
その関数やブロックから出るとグローバル変数の値に戻ります。
このように内側の変数をローカルスコープと呼びます。
Fusion360ポストファイルでは、上部に重要なグローバル変数がまとめて定義されています。
自分で変数を宣言する場合、ローカル変数は、関数内部での寿命なので、それほど気を使う必要はないですが、グローバル変数を定義する場合には混乱を避けるたためにも、定義済みグローバル変数の下段ぐらいにまとめておいたほうが分かりやすいです。
関数スコープ
関数スコープは関数(Function)内で定義された変数です。
違う関数では、変数に同じ名前を使用しても、お互いに影響を与えないため、グローバル変数よりも気楽に使用する事ができます。
Fusion360ポストでテストしてみます。
var global_01; // <----- グローバル変数 var global_02; // <----- グローバル変数 function wtest(){ var local_01 = "R01"; // <---- ローカル変数・関数スコープ var local_02 = "R02"; // <---- ローカル変数・関数スコープ writeln(local_01); writeln(local_02); } wtest();//<------ R01 , R02 が出力される writeln(local_01);// <---- local_01 is not defined
関数外部からは内部で定義された変数は、参照できないのがわかります
ブロックスコープ
ブロックスコープは、関数スコープ内部でさらに、「if」や「for」など { } に囲まれたブロックの内側でしか生き残れない寿命です。
関数スコープよりも短い寿命になりますが、JavaScript言語では、ちょっと複雑なようです。
次で少し掘り下げてみます。
参考サイト
var と let
JavaScript言語では、変数宣言の「var」と「let」では再宣言やスコープが違うようです。
参考サイト
再宣言の可不可
「var」は同じスコープ内で再宣言できるのに対して、「let」はできないようです。
function vartest(){ var x = 0; writeln(x); var x = 1; // 再宣言 writeln(x); }
ポストファイルを編集し、この関数を呼んでみると、やはりエラーはでなくて、「0」「1」が出力されました。
気持ち的には、同じ変数名なので。エラーを出してほしいです。
同じスコープ内で再宣言できるというのは、私はどうも違和感あります、
故意に同じ名前を使いたい場合ならいいですが、特に長いプログラムで誤って宣言してしまった場合トラブルの原因になりそうだし、トラブル時に問題点を探すのも大変です。
なので、やっぱり筆者は「let」の再宣言不可がいいですね!
ということで、Fusion360ポストでも、「let」のテストをしてみました。
function lettest(){ let x = 0; writeln(x); let x = 1; // 再宣言。let なのでエラーになるはず。 writeln(x); }
今度は、「let」で宣言し、呼び出してみました。
うん、なぜだろう??
エラーにならず、「ver」と同じ結果になりました。
試しに、centOS7 に node.js をインストールして確認してみます。
まずは「var」から。
「test.js」ファイルを作成し、実行します。
--- test.js ---- var x = 0; console.log(x); var x = 1; // 再宣言 console.log(x); $ node test.js 0 1
期待通り、再定義でもエラーにならず、出力されました。
次に、「var」を「let」に変更して実行します
--- test.js ---- let x = 0; console.log(x); let x = 1; // 再宣言 console.log(x); $ node test.js /home/kazu/test.js:3 let x = 1; // 再宣言 ^ SyntaxError: Identifier 'x' has already been declared
やはり、JavaScript言語では、エラーになるのが正常のようです。
Fusion360のこの現象はこの記事を書いていて見つかったので、ある意味よかったです。
これは、Fusion360の仕様なのか?バグなのか?
いずれにしても現状ではしょうがないので、Fusion360ポストでの変数は「let」であっても再宣言が許可されていると言うことを認識し、関数内部でも変数はなるべく上部でまとめて宣言するようにして、意識して重複宣言は避けるようにしようと思います。
スコープの違い
さらに、「var」と「let」ではスコープも違うようです。
「var」は関数スコープ。「let」はブロックスコープです。
したがって、関数内部のブロック内で、変数を宣言した場合、「let」はその変数にはブロック内部でしか参照できませんが、「var」はブロックを出ても、関数内であれば、参照できてしまいます。
この違いも、Fusion360ポストでは、発生しないのでしょうか?
そうなると、Fusion360ポストでは、とりあえず「let」を使用してもエラーにはならないが、「var」と同じだと言うことになりますね。
とりあえず、実験してみましょう!
var vx = 1; let lx = 2; writeln(vx); // 1 出力 writeln(lx) // 2 出力 if (true){ // ここからブロック内 vx = 3; // vx に 3 代入 lx = 4; // lx に 4 代入 var vy = "v"; // 新規に var で vy 宣言と"v"割り当て let ly = "l"; // 新規に let で ly 宣言と"l"割り当て } //ブロック終わり writeln(vx); // 3 出力 writeln(lx); // 4 出力 writeln(vy); //v 「var」は関数スコープなので、「"v"」を出力 writeln(ly); //error vy is not defined「let」はエラーが出てくれた!
こちらのテストでは、Fusion360のポストも、スコープの違いは一般的なJavaScript と同じ仕様となりました。
変数の巻き上げ
JavaScript には、「変数の巻き上げ」という、特融の概念もあるみたいです。
なんだか分かりにくい仕様ですが、こちらを参考に、Fusion360でポスト処理してみます。
var xxx =0; function onOpen() { writeln(xxx); var xxx = 1; writeln(xxx); ・ ・
onOpen( )の内部で、「xxx」変数を書きだしてみます。。
最初の「writeln( )」では、「xxx」は外側で、グローバル変数として、
var xxx =0;
と定義されているので、本来ならば「0」が出力されそうな気がしますが、
「undefined」となりました。
これは、onOpen( )関数内部に、
var xxx = 1;
の定義があるからのようです。
不思議な仕様ですね。C言語では、初期化と代入は違いますが、JavaScriptではブロック内に宣言があると自動的に「undefined」で初期化されるみたいです。
なので、「var xxx = 1」は初期化ではなく、代入なんでしょうねぇ
試しに、グローバル変数として定義してる「var xxx = 0」を削除してみました。
ポスト処理の結果は同じデータでした。
てっきりエラーが出るかと思いますが、そうではないようです。
まとめ
JavaScript の構文は、C言語に結構にているので、とりつきやすいですが、変数の仕様はかなり違和感ありました
変数宣言時に右辺で値を割り当てると、C言語では「初期化」になり、その後、別の値を割り当てると「代入」となりますが、
JavaScript では、どこかに宣言があると、自動的に「undefined」で初期化されその後の宣言は、「初期化」ではなく「代入」として扱われる感じですね
また、再宣言に関しては、「var」が可能で、「let」が不可との事なので、「let」のほうが、C言語の変数扱いに近いように思います。
ただ何故なのか?わかりませんが、Fusion360ポストでは同じ結果になってしまいました。
したがって、可能であっても、再宣言は使用しないで、代入としたほうがいいと思います。
Fusion360 ポスト記事
- 概要編
- 構成編
- 変数
- グローバルセクション
- 関数
- NCプログラム仕様検討
- onOpen( )
- onSection( ) No1
- onSection( ) No2
- onSectionEnd( ) & onClose( )
コメント