あと味

たくさん情報を食べて、たくさん発信すると、あとになって味わい深い。

JSONとJSONPの違い

解説は他にもたくさんありますが、私自身も使いはじめの頃、違いがよくわからなかったので。

JSONとは?

汎用的なデータ記述方法です。こんな感じで書きます。

{ 'blog' : 'あと味', 'author' : 'jdg' }

まさにJavaScriptのオブジェクトですね。*1

JSONPとは?

JSONを以下のように変えたもの。

callback({ 'blog' : 'あと味', 'author' : 'jdg' });

関数呼び出しっぽいですね。まぁ、関数呼び出しなんですけど。

どゆこと?となるポイント

見た目が関数っぽくなる意外に変更点はないように見えますが、クロスドメインでJSONを読み込む時は、なぜかJSONではなく、JSONPが使われます。(WebAPI等)

また、アクセスしたらJSON形式のデータを返す単純なCGIを自分で作りたいと思った場合でも、JSONを返しても、JavaScriptで受け取って処理することはできませんが、JSONPを返せば、JavaScriptで受け取って、処理ができます。

そうすると、両者にどういう違いがあるかわからなくて混乱する人がいるようです。な気がします。(過去の私自身も含め)

理解する方法

違いを理解できない原因は、以下の2点かなと考えています。

  1. JSONPを使用するシーンが主にクロスドメインと連携する時なので、特殊な方法だと感じてしまうこと
  2. JSONPはJSONと見た目が少し変わるだけという理解をしてしまうこと

JSONとJSONPの違いを理解するためには、上の2点についての固定観念を捨てることです。

固定観念を捨てる

JSONPでは、callback関数を定義して、引数にJSONを取ることで、JSONのデータを処理できますが、これをひとつのファイルの中で素直に書くとどのようになるか見てみたいと思います。

JSONの場合
var callback = function(json) {
  alert(json.blog + 'の書き手は' + json.author);
}

// (本来なら)外部ドメインから読み込むソース
{ blog : 'あと味', author : 'jdg' }
JSONPの場合
var callback = function(json) {
  alert(json.blog + 'の書き手は' + json.author);
}

// (本来なら)外部ドメインから読み込むソース
callback({ blog : 'あと味', author : 'jdg' });

// callbackという名前が使われることが多いですが、定義と呼び出しの関数名が同一であれば、どんな名前でもOKです。

上記の例でJSONの方は、無反応ですが、JSONPの方は、意図通りアラートが表示されます。

すごく単純な例ですが、コメント以下の部分が外部ドメインにあるだけで、仕組みが理解できないということに陥るようです。な気がしています。

当たり前の話ですが、JSONの例ではcallback関数は呼ばれませんので反応しようがありません。JSONPの例ではcallback関数を呼び出しているので、定義した関数が反応します。

JSONの例のコメント以下の記述は、オブジェクトリテラルを書いてみましたというだけで、変数に格納しているわけでも、関数の引数にしているわけでもありませんので、クロスドメインであろうが同一ドメインであろうが何の意味もない記述です。

JSONPの例のコメント以下の記述は、JSONと見た目が少し変わったものというのではなくて、オブジェクトを引数にした、関数呼び出しです。

理解すればいたって単純な話。違いも明確です。

極端な話、JSONPは以下の記述でも動かすことができます。これも便宜上、同一ファイルに記述してみます。

var hoge = function(json) {
  alert(json.blog + 'の書き手は' + json.author);
}

// 外部ドメインから読み込むソース
var json = { blog : 'あと味', author : 'jdg' };

このように書けば、後はhoge関数の引数に、jsonを入れて、同じような処理ができます。

ただ、クロスドメイン下のJSONPを読み込む際には、callback関数を呼び出すタイミングより先に、jsonオブジェクトが作成されていないといけないので、変数に格納するパターンは使い勝手がよろしくありません。

var hoge = function(json) {
  alert(json.blog + 'の書き手は' + json.author);
}

var script = document.createElement('script');
script.src = 'http://example.com/js/json.js';
document.body.appendChild(script);

/*
クロスドメインのhttp://example.com/js/json.jsは、以下を返す。
var json = { blog : 'あと味', author : 'jdg' };
*/

// この関数呼び出しより先に、jsonの読み込みが完了していないと以下は動かない。
hoge(json);

関数呼び出しの前に、他言語のsleep相当の処理を挟まないといけないので面倒ですね。

なので、JSONPは関数呼び出しの形式にするのが最も良い解ということになります。

まとめ

クロスドメインのJSONは無意味。*2

*1:詳しくは[http://ja.wikipedia.org/wiki/JavaScript_Object_Notation:title=Wikipedia - JSON]で

*2:うわ、適当w