The Good Parts 4章 関数
■4.2 関数リテラル
関数はリテラルでも宣言することができる。| function | 予約語 |
| add_func | 関数の名前(省略可能、IEだとおかしいの省略すべき) |
| a,b | パラメーター |
| {...} | 命令文の集合体 |
var add = function add_func(a, b) {
return a + b;
}
関数リテラルは式であるので、式がかける場所ならどこでも書ける。■ 4.3 関数の呼び出し
関数の呼び出し時にa,bパラメーターとは別にthisとargumentsというパラメータを受け取っている。これらは呼び出しのタイミングによっている値が変わる。
add(1);//と読んだ時bには何も渡されていないので、undefinedで初期化される。
これを応用して、undefinedを取得する事もできる(JavaScriptではundefinedはただの変数なので書き換え可能なため)
undefined = "上書きできてしまう";
(function(undefined){
console.log(undefined);// undefined
})();
■4.3.1 メソッド呼び出しパターン
JavaScriptのメソッドの呼び出しにはドット表記法とブラケット表記法がある。ドット表記法は .名前 に対して ブラケット表記法 [式] となる。
ブラケットは式なので、変数を表すのに変数を使える。
Member Operators - MDC Doc Center
thisは遅延束縛(実行時に何が入るのか決まる)なので、非常に便利なものとなる。
var myObject = {
value: 0,
increment: function (inc) {
this.value += typeof inc === 'number' ? inc : 1;
}
};
myObject.increment();
// thisはmyObjectになる。
■4.3.2 関数呼び出しパターン
ある関数ないからまた別の関数を呼ぶとき、thisの示すものも変化する。そういう時は最初に読んだ時にthisを確保しておいて使う。
var add = function(a, b) {
return a + b;
}
var myObject = {
value: 0,
increment: function (inc) {
this.value += typeof inc === 'number' ? inc : 1;
}
};
myObject.double = function() {
var that = this;// thisの待避
var helper = function() {
that.value = add(that.value, that.value);//thatはmyObjectを指す
}
helper();// thisはwindow
}
myObject.value = 2
myObject.double();
(myObject.value === 4); // true ちゃんと二倍になってる
■4.3.3 コンストラクタ呼び出しパターン
JavaScriptはプロトタイプ継承を行う言語であるので、オブジェクトが他のオブジェクトから直接継承を行う事を意味している。new演算子をつけて呼び出す事を目的として作った関数 = コンストラクタ関数
コンストラクタ関数をnewしてできたもの = インスタンス
そのインスタンス全てで使えるメソッドやプロパティをprototypeプロパティを拡張して作る。
// コンストラクタ関数は大文字から始めるという習慣
var Quo = function(string) {
this.status = string;
};
// get_statusというパブリックメソッドはQuoインスタンス全部で使える
// インスタンスはQuoをnew下ものから生まれたもの
Quo.prototype.get_status = function(){
return this.status;
}
// myQUoというインスタンスを生成
var myQuo = new Quo("confused");
alert(myQuo.get_status());
■4.3.4 apply呼び出しパターン
thisは呼び出し時に自動的に決まるが、そのthisは自分で指定したオブジェクトにすることもできる。applyやcallがそのためのメソッドである。
対して説明されてないので他を見ましょう
■4.4 引数
普通に仮引数を設定してパラメーターを受け取る事もできるが、argumentsという配列に似たオブジェクトを使う事で可変長の引数に対応したりできる。
var sum = function () {
var i, sum = 0;
for (i = 0,len = arguments.length; i < len; i++) {
sum += arguments[i];
}
return sum;
};
arugmentsは実際には配列ではないので、joinやpopなどArrayが持っているメソッドは使えない。実際にそれらのメソッドを持たせるには次のようにする。
var ary_arguments = Array.prototype.slice.call(arguments);
■4.6 例外
try...catchとthrowで例外を投げる方法。これは他の言語とあんまり変わらなそうな感じ。
throwはオブジェクトや文字列など何でも投げられる。
throw Statement - MDC Doc Center
try...catchは遅くなる原因としてあげられることが多いので、ループの外側に貼るなどの必要最小限にする。
try...catchはブロックスコープを作ったり、spiderMonkeyではcatch guardなどの独自拡張があったりする。
var add = function(a ,b){
if(typeof a !== 'number' || typeof b !== 'number'){
throw {
name : "TypeError",
message : "add needs numbers"
};
}
return a + b;
}
// TEST_add
var try_if = function(){
try{
add("seven");
}catch (e){
console.log(e.name + ': ' + e.message);
if(e.name === "TypeError"){
alert("TypeErrorっす");
}else{
alert("TypeError以外だな");
}
}
}
// TEST_add_moz
// mozillaのみのcatchハンドリングの拡張
// https://developer.mozilla.org/ja/Core_JavaScript_1.5_Guide/Exception_Handling_Statements/try...catch_Statement/Exception_Handling_Statements/try...catch_Statement
var try_if_moz = function(){
try{
add("seven");
}catch (e if e.name === "TypeError"){
alert("TypeErrorのみがここにくる");
}
}
try_if();
try_if_moz();
■4.7 変数型の拡張
ObjectやStringなどのprototype拡張の話。拡張を補助するFunction.prototype.methodを作ってNumberなどを拡張していく。
trimはクロージャの話が出てきてないから、毎回正規表現を評価する方法が載っていた。
いろんなtrimの実装方法。(モダンブラウザならネイティブ実装されている)
どうでも良いことだけど、書籍ではFunction.prototype.methodの仮引数のmethod部分がfuncとなっていた。funcと書くとfunctionの補完時に邪魔になるのでできるだけ使わないようにしてる。
Function.prototype.method = function(name, method) {
if (!this.prototype[name]) {// 重複実装は防止
this.prototype[name] = method;
return this;
}
}
Number.prototype.integer = function(){}
/**
* 整数を取り出す拡張
*/
Number.method('integer', function() {
/*
[]の中に式をかけるので、中で三項演算子で分岐してる。
この場合thisは下の例では(-10/3)が来る。
Math["ceil"]((-10/3)); // 3となる。
*/
return Math[this < 0 ? 'ceil' : 'floor'](this);
});
alert((-10 / 3).integer()); // -3
/**
* trimを実装する
*/
String.method('trim', function() {
return this.replace(/^\s+|\s+$/g, "");
});
// => こっちの方が正規表現の評価が最初の一回のみなので効率いい
String.method('trim', (function(reg) {
return function() {
this.replace(reg, "");
}
})(/^\s+|\s+$/g));
alert(" name ".trim());
コメント(0件)
- TB-URL http://efcl.info/adiary/085/tb/