LoginSignup
2
4

More than 5 years have passed since last update.

RPGツクールMVにおけるJavascriptの特殊な判定式の罠を事前に検知するスクリプト

Last updated at Posted at 2016-12-06

はじめに

はじめてのQiita投稿です。お手柔らかに……。
※編集・コメントありがとうございます。即適応させていただきました。
(作者: twitter @merusaia)

RPGツクールMVというツールは、エディタで出来ることもさることながら、
javascriptを使うことで、ツクール至上最も拡張性の高いものに仕上がっていると思います。

他のプログラミング言語を使ってゲームを作っていた人も、
「これはスクリプトを触れば色々出来るんじゃない?」と
ワクワク期待を膨らませられます(筆者はC#から移行してます)。

概要

ですが、CやJava方面から見ると、javascriptの各種判定式は、かなり特殊です。
他の言語と一緒に考えてたら、痛い目みます。。
詳しくは、それぞれのキーワードをぐぐってみてください。罠にハマります。

そこで、なるべくjavascriptの罠にはまらないように、
事前にツクールMVのエディタで、値や各種挙動をチェックできる
スクリプトを作りました。

使い方

ツクールMVのエディタ「スクリプト」で、以下の10行を貼り付けてください。
そして、【好きな初期値】に変数値を入れて、
右クリックメニューで「テスト」してください。

変数「_a」の判定式が、それぞれどんな反応が返ってくるか、事前にわかります。
まだ必要な判定がアレば、お気軽にご指摘・判定式の追加をお願いします。。

var _a = 好きな初期値; // ここの「a = 」の後に【好きな初期値】を入れてね。
alert(
 "「var _a = 【好きな初期値】」の時の判定式だよ。"+"\n_aの値: "+_a
+"\n_a==0: " + (_a==0));
alert(
 "_a instanceof Number: " + (_a instanceof Number) +" // 「0 instanceof Number」はfalseだから、気をつけてね。new Number(0)はtrue。\n_a instanceof String: " + (_a instanceof String) + " //「”あ” instanceof String」はfalseだから、気をつけてね。「new String(”あ”)」はtrue。"
+"\n_a instanceof Object: " + (_a instanceof Object) +"\n_a instanceof Boolean: " + (_a instanceof Boolean)
+"\n_a==undefined: " + (_a==undefined) +"\n_a==null: " + (_a==null) + "\n_a===undefined: " + (_a===undefined) +"\n_a===null: " + (_a===null)
+"\n_a===NaN: " + (_a===NaN) +"\nNumber.isNaN(_a): " + Number.isNaN(_a) + "\nNumber.isFinate(_a): " + (Number.isFinite(_a)) + "\n_a === Infinity: " + (_a === Infinity)   + "\n_a === -Infinity: " + (_a === -Infinity)   
+"\nparseInt(_a): " + parseInt(_a) +"\n_a || 0: " + (_a || 0)       );

番外編:よく忘れる判定式の挙動 (他にもたくさんあるわな)

以下、自分用のメモの貼り付けで恐縮ですが、こんなのがあります。
エディタのコモンイベントなどに一括管理して、よく見返しております…。。
罠だらけだ…><。

◆注釈:判定演算子、isNaN、Number.isNaN、「a || 0」などについてについて。
◆注釈:NaN === NaN は falseです。。。仕様おかしい。。
:  :NaN > 0 はfalseです。
:  :NaN < 0 はfalseです。
:  :NaN != null はtrueです。
:  :NaNの判定には、Number.isNaN(a)を使います。isNaN(a)と書いちゃダメです。信頼性に欠けます。
◆スクリプト:if(NaN < 0){
:     : alert("数えられない数は0より小さいよ。ここは永久に実行されないから注意してね。");
:     :}else{
:     : alert("数えられない数は0より小さく…ないよ。知らないけど。");
:     :}
◆スクリプト:if(NaN > 0){
:     : alert("数えられない数は0より大きいよ。ここは永久に実行されないから注意してね。");
:     :}else{
:     : alert("数えられない数は0より大きく…ないよ。知らないけど。");
:     :}
◆スクリプト:if(NaN != 0){
:     : alert("数えられない数NaNは0じゃないよ。だから比較すらできないから、>や<は全部falseだよ。");
:     :}
◆スクリプト:if(NaN != null){
:     : alert("数えられない数NaNはnullでもundefinedでもないよ。だからNumber.isNaN()でちゃんと比較しないといけないよ。");
:     :}
◆スクリプト:if(isNaN('a')){
:     : alert("isNaN('a')は、falseだよ。"
:     :+"だって、数値"+Number(isNaN('a'))+"に変換できちゃうもんね~。や~いや~い、ひっかかった~(絶望)");
:     :}
◆スクリプト:if(Number.isNaN('a')){
:     : alert("ここは実行されないよ。");
:     :}else{
:     : alert("Number.isNaN('a')もfalseだよ。\n"
:     :+"文字列が入っている可能性があるときは、NaNか調べるときは、Number.isNaN(a)を使おうね。");
:     :}
◆スクリプト:var _num1 = NaN;
:     :_num1 -= 50;
:     :if(Number.isNaN(_num1)){
:     : alert("NaNなものに、何を演算しても、NaNのままだよ");
:     :}

◆注釈:■NaNの仕様がいろいろとよくわからない剣でぶっ刺されるについて
◆注釈:ここ、気をつけて。もはやわけわかめだよ‥。
◆スクリプト:alert(isFinite(NaN)); // falseです。NaNは数えられない数、比較すらできないんですから、当然ですよね。
◆スクリプト:alert(Number.isFinite(NaN)); // falseです。NaNは数えられない数、比較すらできないんですから、当然ですよね。
◆スクリプト:alert(isFinite(Infinity)); // falseです。無限は数えられない? ・・え? そうです・・かね。
◆スクリプト:alert(Number.isFinite(Infinity)); // falseです。無限は数えられない。そうなんですね。
◆スクリプト:alert(Number.isFinite(undefined)); // falseです。そうですよね。
◆スクリプト:alert(isFinite(undefined)); // falseです。そうですよね。
◆スクリプト:alert(isFinite(null)); // trueです。。なぜに。。。
◆スクリプト:alert(Number.isFinite(null)); // falseです。そうですよね。
◆スクリプト:alert(isFinite("12")); // trueです。文字列のままでも、数えられるんだな、これが。
◆スクリプト:alert(Number.isFinite("12")); // falseです。Number.は、そういう卑劣なことは許しません。

◆注釈:ここ、気をつけて。もはやわけわかめだよ‥。
◆スクリプト:NaN === NaN // falseを返す!!!
:     :function isReallyNaN(x) {
:     : return x !== x; // xがNaNであればtrue, それ以外ではfalse
:     :}
◆スクリプト:// 標準で用意されているisNaNにNaNを渡すと確かにtrueが返ります。
:     :// ただ、暗黙の型変換によって引数を数値へと変換してしまう為、NaN自身でなくても、NaNへと変換される類のものに対してもtrueを返してしまいます。
:     :// isNaNはNaNであるかの判定ではなく、引数が数値へ変換可能かどうかの判定に使われるみたいです。
:     :isNaN(NaN); // true
:     :isNaN("foo"); // true
:     :isNaN(undefined); // true
:     :isNaN({}); // true
:     :isNaN({ valueOf: "foo" }); // true
:     :// 新しく作られたNumber.isNaNは、 x != x と同値です。
:     :Number.isNaN(NaN); // true
:     :Number.isNaN('NaN'); // false
:     :alert(Number.isNaN(Infinity)); // false

◆注釈:javascriptでは、Boolean(a)は、
:  :aが値が省略された場合や、値が 0, -0, null, false, NaN, undefined
:  :あるいは空文字列 ("") であった場合、false の初期値を持ちます。
:  :それ以外のあらゆる値は、"false" という文字列も含めて、trueです。
◆スクリプト:alert(Boolean(NaN)); // false
◆スクリプト:alert(Boolean(false)); // false
◆スクリプト:alert(Boolean("false")); // true
◆スクリプト:alert(Boolean(Infinity)); // true

◆注釈:ここ、気をつけて。if(a)は、aがnull, undefinedの時だけじゃなく、0, ""、NaNの時もfalse だよ。
◆スクリプト:var a = '';
:     :alert(!!a); // if(a)がtrueかを返す。if('')はfalse。
:     :a = "";
:     :alert(!!a); // if(a)がtrueかを返す。if("")はfalse。
:     :a = 0;
:     :alert(!!a); // if(0)はfalse。
:     :a = "0";
:     :alert(!!a); // if("0")はtrue。
:     :a = " ";
:     :alert(!!a); // if(" ")はtrue。

◆注釈:「a || 0」という記述はよく見るけど、0、""、NaNの時も0になるよ。特に""が注意!
◆スクリプト:var a = Infinity;
:     :alert(!!a); // if(Infinity)はtrue。
:     :var a = NaN;
:     :alert(!!a); // if(NaN)はfalse。…ええ~~~!????。
:     :
:     :// なるほど。だから以下は、NaNでも0になるのか。
:     :var a = a || 0;
:     :// 上の1行は、下の3行と同じ意味、ですよね。
:     :if(!a){
:     : a = 0;
:     :}

皆さまもお気をつけて……。

2
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4