JavaScriptでnewする、ということ

以下のスクリプトを基本に考える。

function Box(){}
var box=new Box;

Boxはまぎれもなく関数である。正確には関数オブジェクトというらしい(関数もオブジェクトである、という所以か)。コンストラクタですかね。

関数をnewして変数に代入すると、オブジェクトが生成される。それで出来たのがboxだ。通常boxはBoxから派生したのだからBoxで持っていた属性(というかフィールドというか)を引き継ぐ(ここでは何も持っていないので引き継いでいないけれど)。

newして出来たboxはオブジェクトになるわけだが、その際box.__proto__という属性を持つようになる(JavaScript内部でそのような処理が実行されているらしい)。box.__proto__に何が入っているかは後述する。

ここでプロトタイプというものを考える。プロトタイプは関数(ここでいうBox)に対して設定する(オブジェクトboxに設定するものではない)。たとえば上記のスクリプトに追記する。

function Box(){}
Box.prototype.size=1;
var box=new Box;

この状態でbox.sizeは1である。box.sizeは定義も代入もされたことはないけれど1になる。

関数オブジェクトがnewされると、できたオブジェクトに__proto__という属性ができるということは前述した。この__proto__には関数オブジェクトで定義されたプロトタイプ(これもオブジェクトなんだけど)を参照している(ポインタみたいな感じか)。

JavaScriptの仕様で、オブジェクトに特定の属性が存在しない時(ここでいうsize)、当該オブジェクトの属性である__proto__を走査し、sizeという属性を探す。ここでsizeが見つかると、当初のオブジェクトに、いかにもsize属性があるかのごとく、その__proto__.sizeの値を返す。これ、いわゆる継承ってやつですかね。

ちなみに上記のスクリプトで二行目と三行目をひっくり返してみる。

function Box(){}
var box=new Box;
Box.prototype.size=1;

二行目が実行された時点では、box.sizeはundefined。しかし三行目が実行されたらbox.size=1となる。これは__proto__に単純にコピーされたというのではなく参照で渡されているから。元の値が変化すれば、参照している側の値も変化する。

ちょっとわかってきた。

関数の定義方法による挙動の違い

JavaScriptの関数定義方法は大きくわけて二つある(と言い切っていいかどうか分からないけど)。

  1. function hoge(){do something;}
  2. var hoge=function(){do something;};
上記の違いを列挙してみる。
  • 関数定義のタイミング
    1の場合、hogeという関数をコール、つまりhoge()する前に定義しようが、後に定義しようが動作する。つまりJavaScriptがエンジンによってコンパイルされるタイミングで 関数が定義される。
    2の場合、実行時に当該行があったタイミングで関数が定義される。つまり2の記述の前にhoge()するとエラーになる。
  • プロトタイプでメソッドを仕込むときは2の方法を使う。
    1は基本的には使えません(IEでは動くらしいけど)。

Google Analyticsモバイル用がうまく設置できないときに

2011/11/09 | その他

何度か導入したけど、毎回調整しているので調整箇所のメモ。

Google Analyticsモバイル用はいくつかの言語に対応しているのだが、PHPで導入する場合以下の箇所に注意。本体としてはもともと3箇所に手を加える必要がある。それらは以下のとおり。

  1. htmlタグの直前の記述
  2. body閉じタグの直前の記述
  3. /ga.php

2については手を加える必要はない。そのままbody閉じタグの直前に記述すればOK。修正等必要なのは1と3。

そもそもなぜ修正が必要かというと、携帯版専用といえどもPCで確認する場合があるはずで、PCで確認しようとするとエラーが発生するから。そしてエラーはNoticeレベルで発生する。埋め込み画像が壊れるのだ。

修正箇所はいずれも2011年11月09日現在である。

1の13~15行目の記述。

$referer=$_SERVER[“HTTP_REFERER”];

上記のような記述が3行あるので、以下のように変更する。

$referer=empty($_SERVER[“HTTP_REFERER”])? ”:$_SERVER[“HTTP_REFERER”];

同様に、3の140行目から148行目にかけても上記と同様に修正する。

多分携帯で見れば問題ないんだと思う。でも携帯で動作チェックすることはないから、やっぱり上記の修正を加えておくべきと思う。

あと、1の設置場所にhtmlタグの直前とあるが、例えばテンプレートエンジンなど使用していたり、ヘッダとフッタが全ページ共通だから別ファイルにして読み込んでいる場合などは注意が必要。変数のスコープの問題等で2で使用する関数を呼び出せないことがあるからだ。

1については「とにかく一番最初に記述」とすればよさそうだ。PHPではプログラム本体とテンプレートエンジンを使った場合などで、ファイルをインクルードすることも多いはずなので、その一番最初の呼び出し元の先頭に記述すればよい。

データベース利用時のキーをbigintにする必要があるか

2011/10/31 | データベース

結構これに悩む開発者は多いのではなかろうか。

そもそもこういうことに悩むのが間違いの元だと思う。システム開発者たるもの、事前の想定があってそれに対しての開発をするわけで、適当に「将来増加するかもしれないから」なんてことだけで開発してはいけない(とは言っても・・・とも思うけれど)。

MySQLで主キーにauto_incrementを設定すると仮定する。カラムの型がintegerでunsignedの場合最大約42億まで値を確保できる。42億、というと実際には手に届かないが、接したことのある数字である(算数の計算とかの話)。「億」という言葉が問題なのかもしれない。じゃあ「兆」は、「京」はみたいなことをいうと切りがない。なので、まず実際に使用すると思われる量を計算しなくてはならない。

42億というと1日1件の処理で値が1増加すると仮定すれば、約1150万年も使えるわけだ。その頃には人類は絶滅しているんじゃないかと思うので、すでに考えなくていい。

1日100件の処理が行われるとすると、約1万1千年使えるわけだ。人類が絶滅していなかったと仮定してもMySQLは存在しないだろう。じゃ、やっぱり考えなくていい。

1件あたりの処理で値が100増えるとすれば(1日100件の処理で)、101年となるわけだ。さすがに人類はまだ絶滅していなさそうだし、ひょっとしたらMySQLもまだあるかもしれない。でも100年前のシステムの考え方が通用するだろうか。そもそもそれを使う会社が100年先も存在するだろうか(ま、発注者にはそんな事言えないけど)。となれば、これでも考えなくていい。

といった具合に、見積もりを立てれば問題ない。そしてそれを仕様書にまとめて提出する(できれば「こういう仕様でいきます」という事前確認をしておくほうがいい)。

csvファイルをダブルクリックで正常に開く

2011/10/28 | その他

基本的に、WindowsPCならよっぽどこのことがない限り表計算ソフトとしてエクセルをインストールしていることが多いのではないだろうか。

そして、表計算ソフト用として、ウェブからデータをダウンロードする際に多いファイル形式はcsvだろう。

プログラムで出力する際、csv形式でダウンロードさせることが多いが、エクセルとcsvの関係をよくわかっていないと、文字化けしたり、区切り文字が正常に認識されなかったりすることがあるので要注意だ。

まず一番問題ないのが「カンマ区切り、ダブルクォーテーションで値を囲む、文字コードシフトJIS」だ。ダブルクォーテーションで囲むのは各値にカンマが入ってしまうと変なところでセルが分割されるので、それを防ぐためだ。ちなみに各値にダブルクォーテーションが含まれる場合は事前にダブルクォーテーションでエスケープしておく必要がある。

しかし「シフトJIS」というのは日本語用の文字コードであって、例えば中国語などは表現できない。そこで文字コードとしてはUTFな環境をつかいたいわけなのだが、単にUTF-8にするだけではダメだ。

そもそもUTFにはいろいろあって、UTF-7、UTF-8、UTF-16BE、UTF-16LEがある。そしてUTF-7をのぞく3つの形式にはそれぞれBOM付とBOM無があるので、合計7つのUTFが存在するというわけだ。実はこのうち適切に設定するとファイルをダブルクリックすることでエクセルで正しく表示させることが出来る文字コードが存在する。その答えはこうだ。

「タブ区切り、UTF-16LE(BOM付)」

囲み文字のダブルクォーテーションはあってもなくてもよい。ちなみにエクセル2002でも大丈夫。そして「メモ帳」でも文字化けせずに開くことが出来る。知っていると便利だ。


守谷市(まちの情報ポータル) 無料アンケートレンタルjpForm.net