自作のWebアプリがなぜかiPhoneでだけ動かなかった件

知人に頼まれて、完全に趣味の範囲でWebアプリを作ったことがありました。
その際に、「PCやAndroidでは問題なく動くのに、iOS(iPhone)だけJavaScriptが効いてくれない」という問題にぶち当たりましたので、そのことについて書きたいと思います。

知人「僕のiPhoneでアプリが動かないんですけど…」

詳細は割愛しますが、どうやらWebアプリのとある部分でコードをいじってから、知人のiPhoneでうまくJavaScriptが動作していないようでした。
iOSのバージョンは16.5.1、Safariのバージョンは604.1、SafariでもChromeでも同じ症状で動かない、とのこと。
Safariに関しては、apple純正のブラウザですから、挙動の違いがあると言われてもまぁなんとなく理解はできるのですが、なぜChromeもダメなのか?

Safariはわかるけど、なんでChromeも?

いろいろ調べていると、こちらの記事を発見。
なるほど、同じブラウザをインストールしていても、OSがiOSだとレンダリングエンジン(心臓部)はすべてWebKitだから、コードの書き方によっては同じブラウザで見ていても挙動が違うということがあるらしい。

私自身はAndroidユーザーで、社内でアプリ開発をする際は職場のiPhoneを使って実機テストをしているため、プライベートではiPhoneを所有していません。
でもそうなるとエラーの再現ができないので、iPhone実機に近い形で検証をする方法を探しました。

こちら参考に、Node.jsのPlaywrightというライブラリをインストールし、使用しました。
使い勝手的なところは、またの機会に書けたらと思います。

Playwrightでデバッグできた!

なるほど、Playwrightのデバッグコンソールで確認すると、ちゃんとエラーが出てる。
ていうかstackoverflowにもおんなじ質問してる人いた。

今回のエラーの原因

起きてる事象が同じだったので、さきほどのstackoverflowの質問に回答されていた方の、サンプル検証コードから引用させていただきました。

document.write("スクリプトの先頭では `foo` の type は `" + typeof foo + "` です。<br/>")

{
    document.write("ブロックの先頭では `foo` の type は `" + typeof foo + "` です。<br/><br/>")

    const message = "Hello"

    foo()

    function foo() {
        document.write("foo 内での `message` の type は `" + typeof message + "` です。<br/>")

        if (typeof message == "undefined") {
            document.write("foo 内では `message` は未定義です。<br/>")
        } else {
            document.write("foo 内での `message` の値は `" + message + "` です。<br/>")
        }
    }
}

・Webkit系のスクリプトエンジンでは、関数の宣言がスクリプトの先頭まで巻き上げられます。その結果、ブロックの外に出てしまい、当該変数を参照できなくなります。
・その他の処理系では、関数の宣言はブロックの先頭まで巻き上げられます。依然としてブロックの中なのでブロック内の変数を参照できます。
Webkit系の出力:
 foo 内での message の type は undefined です。
 foo 内では message は未定義です。
FirefoxとChromeの出力:
 foo 内での message の type は string です。
 foo 内での message の値は Hello です。

JavaScriptがiPhoneでのみ正常に動作しない

つまり、関数の外で宣言した変数を、FirefoxとChromeでは参照してくれるが、Webkit系では参照できずundefinedになるというのが原因でした。
私の場合は、対策その3: 関数式を用いることで解決しました。

Safariだけ動かない事象は他にもあるっぽい

今回の私のケースとはちょっと違うのですが、おもにDateクラスを使うときや、正規表現の書き方などで思ったような挙動にならないことがあるようです。ご参考まで。

この記事が気に入ったらサポートをしてみませんか?