Kinopyo Blog

プログラマとしてRuby, Rails, iPhone, iPad,Macなどなどと向き合う日々のログポース

Posts Tagged ‘JavaScript’

Javascript変数にブロックスコープはない

2010年02月12日

JavaをやってからJavascriptを触ったので、

Javascript変数にブロックレベルのスコープがないことにビックリしました。

if文ブロックか、forループブロックか関係なく、

function内に定義された変数は全て同じスコープ:functionのスコープになります。


例えば

function test(o) {

    var i = 0;                      // i is defined throughout function

    if (typeof o == "object") {

        var j = 0;                  // j is defined everywhere, not just block

        for(var k=0; k < 10; k++) { // k is defined everywhere, not just loop

            document.write(k);

        }

        document.write(k);          // k is still defined: prints 10

    }

    document.write(j);              // j is defined, but may not be initialized

}


変数kとjはそれぞれif文のブロック、forループのブロック内に定義されたが、

実はfunctionのスコープとなりfunction内ならどこでも参照できます。


これをしっかり理解しないと以下のようなミスが起こしやすいです。

var scope = "global";

function test( ) {

    alert(scope);         // Displays "undefined", not "global"

    var scope = "local";  // Variable initialized here, but defined everywhere

    alert(scope);         // Displays "local"
}

test( );


一番目のalertは”global”だと思ったらこの記事を読む価値はあるでしょう。

一番目のalertは”undefined”を表示します。

なぜならさっき言ったように変数のスコープはfunction内に跨るのです。

varで宣言する位置、順番と関係ありません。


ここではfunction内で同じ名前でscopeという変数が宣言され、

“global”の値を持つグローバル変数は上書きされました。

そして一番目のalert時のscopeは初期化されていないため、undefinedとなってしまいます。


上記のコードを書き換えると以下と同じです。

function test( ) {

    var scope;       // Local variable is declared at the start of the function

    alert(scope);    // It exists here, but still has "undefined" value

    scope = "local"; // Now we initialize it and give it a value

    alert(scope);    // And here it has a value

}

誤解を招かないように変数の宣言はfunctionの先頭に置くのが大事ですね。

Javascript window.openで開いたページで親ウィンドウのdocumentを取得には

2010年01月29日

window.open()で新規開いた小窓ウィンドウで親ウィンドウのdocumentを取得するには

下記のプロパティを使います。

window.opener.document

これで親ウィンドウの値を取得するだけではなく、

値を編集することもできます。


例えば下記のコードは親ウィンドwのフォーム内のテキストをAAAに変更します。

新規開いたページに記述します。

window.opener.document.FORM1.TEXT1.value = "AAA";

参考サイト

とほほのJavascriptレファレンス:ウィンドウオブジェクト

jQueryでiFrame内のXML Documentを指定する方法

2009年12月22日

iframeでXMLを読み込んた場合、XMLのdocumentを正しく指定すれば

普通のDOM操作のようにXMLに対して操作できます。

FirefoxとIEの取り方が異なるため、その方法を紹介します。


サンプル

こんなXMLファイルの中の各name要素のテキストを取るとします。






    World of Warcraft

    Warcraft III

    StarCraft

    Final Fantasy


IEの場合XMLDocument


$("iframe").attr("src",xmlUrl).one("load", function(){

    var xmlDocument = this.contentWindow.document.XMLDocument;

    $(xmlDocument).find("game").each(function(){

        var game = $(this).text();

       // ほかの処理

    });

});

Firefoxの場合ActiveElement


$("iframe").attr("src",xmlUrl).one("load", function(){

    var xmlDocument = this.contentWindow.document.ActiveElement;

    $(xmlDocument).find("game").each(function(){

        var game = $(this).text();

       // ほかの処理

    });

});

xmlUrlは実際XMLファイルのURLです。

参考サイト

下記の英語掲示板で見つけたんです。

How to Get XML Document from iFrame

テキストボックスの文字列を選択(色逆転)、取り消すには

2009年12月10日

テキストボックスの文字を選択された状態にする方法とその解除方法です。

IEの場合selectボックスにselect()関数を使うとJavaScriptエラーになります。

Firefoxは大丈夫です。


function selectFocusText(element){

	// for IE

	if (element.nodeName == "SELECT") return;

	element.select();

};

function unselectFocusText(){

	// for IE

	if (document.selection) {

		document.selection.empty();

	// for Firefox

	} else if (window.getSelection) {

		window.getSelection().removeAllRanges();

	}

};

拡張子が変更されたJavaScriptは実行されるか?IE,Firefoxでのセキュリティ

2009年12月02日

ここが危ない!Web2.0のセキュリティ:第1回 Ajaxとクロスサイトスクリプティング|gihyo.jp … 技術評論社の勉強メモ&実験です。

実験

あるJavaScriptの拡張子をcsvに変更してSCRIPTタグでそれをインポートするHTMLを用意します。

そのJavaScriptを実行しようとするとIEのデフォルトセキュリティオプションでは、

ファイルのダウンロードダイアログが出ます。

Firefoxは拡張子がcsvにもかかわらずちゃんとJavaScriptと認識してそれを実行します。

原理

CSVファイルは単にカンマで区切られたデータですので,スクリプトは実行されないはずです。

Internet Explorerの仕様にセキュリティ設定に「内容によってファイルを開く」という設定ががあります(図2)。

これは,Internet Explorerがファイルの中身を見て,その中にHTMLっぽい文字列が含まれていればHTMLだと判断するということを意味しています。このため拡張子やレスポンスに含まれるContent-Typeヘッダとは関係なく,外部から参照可能なファイルにはクロスサイトスクリプティング対策が必要であるということになります。

一方,Firefoxの場合はレスポンスのContent-Typeヘッダを見て判断しますので,ファイルの中身が何っぽいのかを気にする必要はありません。

http://gihyo.jp/dev/serial/01/web20sec/0001?page=2

この観点からはIEのほうがセキュリティの面で高いと見られます。

iPhoneでページ最下部へ移動するブックマークレット

2009年11月27日

ブックマークレット(Bookmarklet)とは

簡単に言うとJavaScriptをブックマークしたものです。

普通はURLをブックマークするに対し、JavaScriptをブックマークします。

そしてこのブックマークを選ぶときは保存されたJavaScriptが実行されます。

iPhoneのブラウザ関連のアプリでは結構使われています。

最下部へ移動するJavaScriptをiPhoneに登録する方法

javascript:window.scrollTo(0,document.documentElement.scrollHeight);
  • まずSafariで任意のサイトをブックマークする
  • そのブックマークを編集する
  • 一行名に好きな名前(ここではPage Bottom)を記入し、二行目を上記のJavaScriptを貼付けで保存する

f:id:kinopyo:20091128002653p:image

  • ページの最下部へ移動したい時はブックマークからさっき登録したブックマークレットをタップすればOK。

f:id:kinopyo:20091128002655p:image


参考サイト:

http://css-eblog.com/javascript/scrolltoend-for-iphone.html

ブックマークレットとは – はてなキーワード

IE JavaScript実行した際の「アクセスが拒否されました」メッセージ

2009年11月19日

経緯

iframeで動的に画面を読み込む際URL不正などによる通信エラーが起こした場合の

エラーハンドラを追加したかったので判断するロジックが必要でした。

わざと誤ったURLを渡して検証しましたが、以下のコードはだめでした。


// documentがnullかと思ってそれで判断しようとしたんです。
if (this.contentWindow.document) {}

現象

あるプロパティは存在しているのに、アクセスができない。コードで書くと

// プロパティがオブジェクトに存在するかを判断
// ここはアラーとが出した、つまり存在したってこと
if ("aProperty" in obj) alert('obj has aProperty');
// 次にそのオブジェクトにアクセスしようとすると
// エラーになった
obj.aProperty

IE8の開発ツールで見たら「アクセスが拒否されました」と書いてある。

f:id:kinopyo:20091119133655j:image


エラーをcatch

判断のロジックをtry-catch文に書けばいいです。

try {
this.contentWindow.document;
} catch (e) {
if (e.number == -2147024891) {
//アクセスが拒否されました。
alert(e.message);
} else {
alert("別のメッセージ");
}
}


参考サイト:http://sei.qee.jp/docs/freetalk/2009/02.html

JavaScript: argumentsは配列じゃない、配列のメソッドを使うには

2009年11月18日

argumentsは配列じゃないため、配列のメソッドは

使えません。ということは本を読んだとき当たり前だと思ったんですが、

実際コードに落としたときは

自然とargument.slice()を書いちゃいました。

argumentsで配列のメソッドを使うには

Array.prototype.<配列のメソッド>.call(arguments,<パラメータ>)

Array.prototype.slice.call(arguments,2)

上記の意図としてはarguments.slice(2)の表現に近いです。

argumentsはarray-likeオブジェクト

ここでちょっとargumentsの基本知識を復習します。

length属性もあるし、[]でindex指定のオブジェクトを参照できますけど、

argumentsは配列に似ているオブジェクトだけです。

予約語

Technically, argumentsは予約語ではないですが、

予約語として認識してよいです。

つまりargumentsという変数は作成しないでってことです。


function foo(x){
alert(x);
var arguments;
arguments[0] = null;	//xの値が変更されちゃう
alert(x);	// null が出力される
}
callee Property

Refers to the function that is currently being executed.

今実行中のファクションを参照しています。

function(x) {
if (x <= 1) return 1;
return x * arguments.callee(x-1);
}


 

クライアント側のActiveXが有効か無効かを検出するJavaScript

2009年11月17日

知っておくべきこと

  • ActiveXはIE専用のものと理解してよい、Firefoxなどでは存在しない
  • new ActiveXObject(“Microsoft.XMLHTTP”)でIEのXMLHttpRequestが生成される
    • IE のバージョンによっては、”Microsoft.XMLHTTP”の代わりにこれらも使用できるそうです:
    • “Msxml2.XMLHTTP.5.0″
    • “Msxml2.XMLHTTP.4.0″
    • “Msxml2.XMLHTTP.3.0″
    • “Msxml2.XMLHTTP”
  • もし生成できればActiveXコントロールは有効になっている


検出ソースコード

// ブラウザがIEの場合
if (window.ActiveXObject) {
try {
//IEのXMLHttpRequestオブジェクトを試しに生成
var xhr = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
alert('ActiveXコントロールは無効になっています');
}
}


参考サイト

動画をHTMLに埋め込むヒント – faireal.net

JavaScriptにオーバーロードはない

2009年10月24日

javaをやってからJavaScriptにかえると、

なかなかなれませんね。


例えばJavaではオーバーロードができるが、

JavaScriptには通用しない。


すごく簡単に言うと、オーバーロードは多重定義の意味で、

同じメソッド名で違う型、数のパラメータがある時、それぞれ一つのメソッドとして認められる。

一方、JavaScriptでは後勝ちです。

先に定義したものが無効になります。

function func(param) {
alert(param);
}
function func() {
alert(1);
};
func("test");
func();

同じfuncの名前で作られた関数で、一個目はparamというパラメータがついてる。

二番目はパラメータがない。

すると結果は: 1 1 になります。

常に後で定義したものが勝ちます。


function func(){
alert(1);
};
function func(param){
alert(param);
}

これは「test undefined」になります。