突然起動しなくなったファイルサーバ(Windows2000)の復旧
今日、客先で利用させてもらっていたWindows2000のファイルサーバに、突然ブルースクリーンが表示。
おいおい、と思いながら再起動すると
missing operating system
げげっ!シャレにならん!
実際にこんなエラーに遭遇するのは初めてだったのでかなり焦る。
ググって調べると、MBR(マスター・ブート・レコード)が破損している可能性があるらしいので
インストールディスクを借りて回復コンソールを立ち上げ、fixmbrコマンドを打ち込む。
再起動すると、
error loading operationg system
オーマイガー!! なんかさらにひどくなってそうなエラー表示が・・・
回復コンソールでCドライブにアクセスしようとすると、
「エラーが起きてアクセスできません」
mapコマンドでドライブの情報を表示させると、
Cドライブのファイルフォーマットが表示されていない。
ファイルシステムが破損しているのか!!?
マズい!ほんとにマズい!!
OSのブートレコードが破損している可能性もあり、fixbootコマンドで修復できるらしいことがわかった。
でも、ド素人がこれ以上いじくる前に最低限必要なデータはバックアップを取らねば!
と、調べていると、CDから起動できるKNOPPIXというLinuxを使って、データのバックアップが
できることがわかった!
早速CD-Rに焼いて、CDから起動。
1分ほどできれいなデスクトップが表示された。
「おぉ〜、なんかすごい」とちょっと感動。
デスクトップには、自動でマウントしてくれたドライブへのショートカットアイコンが。
すごい、すごいぞKNOPPIX!
Cドライブにマウントしたディレクトリにアクセスしようとすると
Could not open ・・・・(忘れた)・・・
開かない! ファイルフォーマットが特定できないからマウント失敗でーす、みたいなこと言ってる・・・
バックアップできず・・・
もしかして、Cドライブがイカれたか・・・いや、ブートレコードが破損しているだけの可能性も。
もはやバックアップはあきらめて、最後の光「fixboot」コマンドをたたくしかない。
恐る恐るfixbootしてみると、
ブートレコードが破損しています。 ブートレコードを修復しました。
と表示された。祈りながら再起動すると、OSを認識!!!!
見慣れた起動画面が表示されました。
た、助かった!
速攻で別のマシンに必要なデータをバックアップしました。
うちのPCもこんな状態にならないうちにバックアップしないと、と思わせてくれた出来事でした。
calleeとthisで参照できるオブジェクト違い
呼び出されるたびに異なる値を返す関数として、
関数プロパティに変数を保持させて実現する例があった。
uniqueID = function() { if (!arguments.callee.id) arguments.callee.id = 0; return arguments.callee.id++; }; alert(uniqueID()); // 0 alert(uniqueID()); // 1 alert(uniqueID()); // 2
calleeじゃなくて、thisじゃだめなの?
と思い試してみると、
uniqueID = function() { if (!this.id) this.id = 0; return this.id++; }; alert(uniqueID()); // 0 alert(uniqueID()); // 1 alert(uniqueID()); // 2
な〜んだ、同じ結果じゃーん。って思っていたら、全然違う動作をしていた。
calleeを使った場合だと、idプロパティはFunctionオブジェクトのプロパティ。
thisを使った場合だと、呼び出し元、つまりGlobalオブジェクトのプロパティとして生成される。
試しに、alert(id); ってやってみると、「3」がアラートされました。
関数の中のthisは、呼び出し元のオブジェクトを参照するキーワードなので
Globalな関数の中のthisは、Globalオブジェクトとなります。
JavaScript第5版 P144 クロージャの例
クロージャとは、実行するコードとコードを実行するスコープを組み合わせたもの
//呼び出されるたびに異なる値を返す関数 //関数のプロパティに変数を保持させて実現する場合 uniqueID = function() { if (!arguments.callee.id) arguments.callee.id = 0; return arguments.callee.id++; }; alert(uniqueID()); // 0 alert(uniqueID()); // 1 alert(uniqueID()); // 2 uniqueID.id = 0; alert(uniqueID()); // 0 関数の外から値を変更できてしまう //クロージャを使えば、この問題は解決できる uniqueID = (function() { var id = 0; return function() { return id++; }; })(); alert(uniqueID()); // 0 alert(uniqueID()); // 1 alert(uniqueID()); // 2 uniqueID.id = 99; alert(uniqueID()); // 3 alert(uniqueID.id); // 99
実行コンテキストとスコープチェーンについて整理した
JavaScript第5版「変数のスコープの概念」の説明でこんがらがってしまったので整理してみた。
- グローバル変数はGlobalオブジェクトのプロパティ
- Globalオブジェクトはインタプリタ起動時にJavaScriptコードを実行する前に生成される
- ローカル変数はCallオブジェクトのプロパティ
- 個々の関数がコールされるたびに、関数ごとに新しい実行コンテキストが生成される
- 関数外部のJavaScriptコードの実行コンテキストでは、Globalオブジェクトが変数定義に使われる
- 関数内部でJavaScriptコードの実行コンテキストでは、Callオブジェクトが変数定義に使われる
- JavaScriptの実行コンテキストには、コンテキストごとにスコープチェーンがある。
- スコープチェーンはGlobalオブジェクトやCallオブジェクトを並べたもの
実行コンテキスト=(Globalオブジェクト|Callオブジェクト)と一瞬思ったが
よく読むと別物のようだ。
なんだか文章ではわかりにくいかったので、絵で描いてみた。
実行コンテキストにGlobalオブジェクトやCallオブジェクトへの参照が存在するイメージ。(たぶん)
(絵の中ではオブジェクトが存在するように書いてますが)
JavaScript第5版 P123〜P140
関数
- 関数もオブジェクト
- 関数はデータとしても扱える
- 関数の引数は省略可能
- 可変長引数(argumentsプロパティで参照できる)
- argumentsの実態は配列のようなArgumentsオブジェクト
- arguments.calleeで実行中の関数を参照できる
- arguments.callee.lengthで関数定義時の引数の個数を取得できる
function square(x) { return x*x; } //function文 var square = function(x) { return x*x; } //関数リテラル //引数は省略可能 function f(x, y, z) { ・・・ } f(1); // x == 1, y == undefined, z == undefined f(1, 2); f(1, 2, 3); //可変長引数 function max() { for (var i = 0; i < arguments.length; i++) { /* 渡された引数の中で最大値を返す */ } }
- thisキーワード
- メソッドを呼び出すときに使用したオブジェクトが、メソッド本体でthisによって参照できる
apply() と call()
あるオブジェクトのメソッドであるかのように関数を呼び出せる
- 最初の引数は対象となるメソッド。関数本体のthisキーワードの値となる
- 2番目以降は関数の引数
f.call(obj, 1, 2); //以下は上の例とほぼ同じ意味になる obj.m = f; obj.m(1, 2); delete obj.m;
apply()は関数に渡す引数を配列で渡す点でcall()と異なる
f.apply(obj, [1, 2]); //配列の要素の中から最大値を見つけたいときに便利 var max = Math.max.apply(null, array);
JavaScript第5版 P105〜P122
配列のメソッド
join
配列の要素を文字列に変換し、連結する。
var a = [1, 2, 3]; var s = a.join(); // s == "1,2,3" s = join(", "); // s == "1, 2, 3" 区切り文字指定
reverse
配列の要素の順番を逆にする。新しい配列は作らない。
var a = [1, 2, 3]; a.reverse(); // a == [3, 2, 1]
sort
配列の要素をソートする。新しい配列は作らない。
var a = ["banana", "cherry", "apple"]; //引数がない場合はアルファベット順にソートする a.sort(); // a == ["apple", "banana", "cherry"] a = [5, 11, 4, 3, 1]; //ソート関数を指定した場合は関数に従ってソートする a.sort(function(a, b) { //小さい順にソートする return a - b; //aをbよりも前にしたい場合は0より小さい数字を返す });
concat
配列に要素を追加して、新しい配列を生成する。
var a = [1, 2, 3]; a.concat(4, 5); // [1, 2, 3, 4, 5] a.concat([4, 5]); // [1, 2, 3, 4, 5] a.concat(4, [5, [6, 7]]); // [1, 2, 3, 4, 5, [6, 7]] 配列を再帰的には展開しない
slice
部分配列を返す。元の配列は変化なし
var a = [1, 2, 3, 4, 5]; a.slice(2, 4); // [3, 4] 2番目の要素から4番目の要素まで(4番目は入らない) a.slice(2); // [3, 4, 5] a.slice(1, -1) // [2, 3, 4]
splice
配列に要素を挿入したり、配列から要素を削除したりする汎用的なメソッド。
元の配列を変更する。
var a = [1, 2, 3, 4, 5, 6]; //要素を削除し、削除した要素を配列で返す a.splice(4); // [5, 6], a == [1, 2, 3, 4] a.slice(1, 2); // [2, 3], a == [1, 4] a.slice(1, -1) // [2, 3, 4] //要素の追加、置き換え a = [1, 2, 3, 4, 5]; a.splice(2, 0, 'a', 'b'); // [], a == [1, 2, 'a', 'b', 3, 4, 5] a.splice(2, 2, [7, 8], 9); // ['a', 'b'], a== [1, 2, [7, 8], 9, 3, 4, 5] // 配列は展開せずに挿入される
push, pop
配列の最後に要素を追加し、配列の長さを返す。(push)
配列の最後の要素を削除し、削除した要素を返す。(pop)
var stack = []; stack.push(1, 2, 3); // 3を返す。 stack == [1, 2, 3] stack.pop(); // 3を返す。 stack == [1, 2]
unshift, shift
配列の先頭で出し入れする。
追加がunshift。削除がshift。
var a = []; a.unshift(1, 2); // 2を返す。 a == [1, 2] 一括挿入は順番を保持 a.unshift(3); // 3を返す。 a == [3, 1, 2] a.shift(); // 3を返す。 a == [1, 2]
JavaScript第5版 P91〜P104
for/in文
オブジェクトのプロパティごとにループが実行される
var obj = new Object(); obj.a = 3; obj.b = "abc"; obj.c = function() { alert("call z"); }; obj.d = [1,2,3]; obj.e; for (var prop in obj) { alert(prop); //a、b、c、dの順番に表示 }
var文
var文で変数を宣言すると、宣言する場所が関数内であれば、その関数のCallオブジェクトのプロパティとして生成する。関数外であれば、グローバルオブジェクトのプロパティとして生成する。
function文
JavaScriptパーサが関数定義を検出すると、var文と同様にCallオブジェクトのプロパティとして関数を生成する。関数は定義されるだけで実行はされない。
alert(f(5)); // 25が表示される。定義前でも呼び出せる var f = 0; function f(x) { // 関数の定義は、f=0 よりも先に行われる return x * x; } alert(f); // 0が表示される。f()は上書きされている
with文
指定したオブジェクトがスコープチェーンに追加される
with(frames[1].document.forms[0]) { // forms[0]に直接アクセスできる name.value = ""; address.value = ""; }
しかし、コードの最適化が難しく実行速度が遅くなるのが欠点。
withはあまり使わないほうが良いみたい。
空文
「;」だけ。何もしない文。役に立つこともある。
//配列aの初期化 for (var i = 0; i < a.length; a[i++] = 0) ; //ループ本体は空