ページ 12

【解決済み】meta undefinedが回避できない

Posted: 2021年6月05日(土) 12:57
by ドラムカン
いつもお世話になります。

一部スキルのメモ欄に<testSkill>と記述し、
以下のように参照して条件分けをしようとしております。

コード: 全て選択

    var list = $gameActors.actor(1).skills();

    for (var key in list) {
        if(list[key].meta.testSkill == true){
	    //処理
        }
    }
メモ欄に<testSkill>がない場合は、undefinedで、
ある場合はTrueが返ってくるのですが
undefinedとTrueの判定が終わった時点で
cannot read property 'testSkill' of undefined となり
強制終了となってしまうため
これを回避すべく、条件式を==にすると
undefinedもNull扱いになるらしいので、以下のようにしてみたのですが

コード: 全て選択

 if(list[key].meta.testSkill == null){
なぜかundefinedになって強制終了してしまいます。

試しに、<testSkill>がメモ欄にあるスキルのみをアクターID1のアクターに覚えさせて
戦闘してみると、なんと同じくcannot read property 'testSkill' of undefinedエラーで強制終了となりました。

<testSkill>タグの有無にかかわらず、undefinedとなってしまう理由は
一体どこにあるのでしょうか?

ご教示いただけますと幸いです。
どうかよろしくお願いいたします。

Re: meta undefinedが回避できない

Posted: 2021年6月05日(土) 14:01
by WTR
list[key].meta.testSkill  に対して
cannot read property 'testSkill' of undefined
というエラーが出たならそれは
'testSkill' が undefined だという意味ではなく
"." ピリオドで区切られた手前のオブジェクト… meta が undefined だということかと。
冷静に読むと英文のメッセージも 'testSkill' of であり 'testSkill' のことは言っていないですね。

Re: meta undefinedが回避できない

Posted: 2021年6月05日(土) 14:33
by ecf5DTTzl6h6lJj02
こんにちは。
ドラムカン さんが書きました:

コード: 全て選択

    var list = $gameActors.actor(1).skills();

    for (var key in list) {
        if(list[key].meta.testSkill == true){
	    //処理
        }
    }
処理 と 書かれている部分は実際にコードが書かれているはずですが、
どんなコードになっていますか?
このコードなら、if 条件文の部分は問題なく通るはずなので、
その後の処理に問題があるものと推測します。
実際、こちらで

コード: 全て選択

let list = $gameActors.actor(1).skills();
for(let key in list){
    if(list[key].meta.testSkill == true){
        console.log(`${list[key].name} has <TestSkill> tag.`);
    } else {
        console.log(`${list[key].name} dose not have <TestSkill> tag.`);
    }
}
というコードを書いてみたところ、
問題なく通りましたので。

Re: meta undefinedが回避できない

Posted: 2021年6月05日(土) 14:37
by ドラムカン
WTR様

いつもお世話になります。
ご回答いただき、ありがとうございます。

しかし、metaですとエラーは出ないのです。
if(list[key].meta == true){

どのスキルのメモ欄にも必ずなんらかの情報が入っており
その情報はしっかりと取得できます。
スキルのメモ欄の配列も取得でき、中にはtestSkillの情報もコンソールログから参照できます。

meta が undefined というのは、どういうことでしょうか?
Nullはオブジェクトに対して使われ、undefinedは値に対して使われるものと認識しておりますが
この場合、metaに値が存在しないスキルが無いため、出るわけがないのですが
なぜこのようなことが起こるのでしょうか?

Re: meta undefinedが回避できない

Posted: 2021年6月05日(土) 14:50
by ドラムカン
ecf5DTTzl6h6lJj02 様

いつもお世話になります。
ご回答いただきまして、ありがとうございます。

//処理
の部分には、console.logのみで実行した際もエラーが発生しましたので
その処理自体には問題がなく、当該のif文を追加すると起きる現象となっております。

頂戴いたしましたコードを早速試してみましたところ、
Identifier 'list' has already been declared
というエラーが発生いたしました。
ecf5DTTzl6h6lJj02 様の環境では問題ないとのことで
エラーが出た際、どこでエラーが出ているのか確認しましたところ
以下の部分がSearchされておりました。

rpg_managers.js:1949

コード: 全て選択

SceneManager.catchException = function(e) {
    if (e instanceof Error) {
        Graphics.printError(e.name, e.message);
        console.error(e.stack);   //ここで停止
    } else {
        Graphics.printError('UnknownError', e);
    }
    AudioManager.stopAll();
    this.stop();
};
このエラー箇所は、当方のコードでも全く同じでした。
何か解決の糸口はございますでしょうか?

Re: meta undefinedが回避できない

Posted: 2021年6月05日(土) 14:53
by WTR
ecf5DTTzl6h6lJj02 さんのご指摘のように、結局のところ省略されている処理の内容に何かあるんだと思います。

meta だけが undefined というのは普通ないですね。
自分で書いておいてなんですが、意図して消さなきゃそんなことにはならないと思います。

処理の中で list の要素を間違えて書き換えちゃっているとか…
list の要素がスキルオブジェクトでなくなってしまってたら meta なんて知らないよ、ってことはありうるかと。

Re: meta undefinedが回避できない

Posted: 2021年6月05日(土) 14:56
by ドラムカン
WTR様

ご回答ありがとうございます。

//処理の部分には問題ございません。
当該のif文を除外すると正常に走ってくれますので。

Re: meta undefinedが回避できない

Posted: 2021年6月05日(土) 15:11
by 奏ねこま

コード: 全て選択

var list = $gameActors.actor(1).skills();
まず、ここで取得したlistは配列です。

コード: 全て選択

    for (var key in list) {
        if(list[key].meta.testSkill == true){
       //処理
        }
    }
ここでfor inにlistを渡していますが、for inは配列で使用してはいけません
keyに添字以外のプロパティが返ってくることがあるためです。
プラグインが導入されていないまっさらなプロジェクトなら添字だけが返ってくると思いますが
Arrayクラスにプラグイン独自のメソッドやプロパティが追加されているとそれがkeyになることがあります。
なので、

コード: 全て選択

    for (var skill of list) {
        if(skill.meta.testSkill == true){
       //処理
        }
    }
このように、配列ではfor ofを使用することをオススメします。

Re: meta undefinedが回避できない

Posted: 2021年6月05日(土) 15:29
by 名無し蛙
おそらくコード自体には問題はなく書いてない部分に何か原因があるとは思うんですが
それとは別に二点気になる部分があります。

まずfor...in文について。
2021年現在JavaScriptでの使用は非推奨とされています。
for...ofやforEach+アロー関数等、十分な代替手段は用意されているので今後は使用しない方が良いです。

コード: 全て選択

const list = $gameActors.actor(1).skills();
for(skill of list) {
    if (skill.meta['testSkill']) {
    }
}
もう一つは
ドラムカン さんが書きました:これを回避すべく、条件式を==にすると
undefinedもNull扱いになるらしいので、以下のようにしてみたのですが
これはおそらく等価演算子と厳密等価演算子の挙動の違いに関する話だと思いますが今回は特に関係無いと思います。
ドラムカン さんが書きました:頂戴いたしましたコードを早速試してみましたところ、
Identifier 'list' has already been declared
というエラーが発生いたしました。

コード: 全て選択

var list = $gameActors.actor(1).skills();
let list = $gameActors.actor(1).skills();
おそらくこのような横着が原因です。
既にlistという変数が定義されているスコープで
letまたはconstで同名の変数を新たに定義した場合に発生します。varでは発生しません。

一連の流れからの印象ですが、一つ一つは問題なくとも
細かい知識不足の積み重ねでエラーが発生し易いコードを書いてしまっているのだと思います。
スクリプトは動けば良い、というものではなく
機能を拡充し続ける為の拡張性、エラーを発見し易い保守性等も重要な要素です。
一度javascriptに関するtipsについて勉強しても良い頃合いではないでしょうか。

※追記で
ちょっと調べ直したらfor-in自体は非推奨ではなく分割代入型と呼ばれるfor-inが非推奨なだけでした。
今回の使用はねこまさんの指摘通り不適切だと思いますが
誤った知識を書いた事に関して訂正させていただきます。

Re: meta undefinedが回避できない

Posted: 2021年6月05日(土) 15:34
by WTR
奏ねこま さんが書きました:for inは配列で使用してはいけません。
そういうものなんですねー
自分で for...in って書こうと思ったことがなかったので気にしたこともなかったです。

ただいまいち納得がいかないのは
エラーメッセージが cannot read property 'testSkill' of undefined だということ…

意図していない key になっていて list[key] が取得できないなら
cannot read property 'meta' of undefined になりそうな。
意図通りかどうかは別として list[key] までは何らかの形で取得できてるのかなぁ…とさらに謎が。