JavaScriptの隠された機能?[閉まっている]


312

JavaScriptのどの「隠された機能」をプログラマは知っておくべきだと思いますか?

次の質問への回答の質の高さを見て、JavaScriptに質問するときがきたと思いました。

JavaScriptはおそらく現在最も重要なクライアント側言語です(Googleに聞いてください)が、ほとんどのWeb開発者がJavaScriptが実際にどれほど強力であるかを理解していないのは驚くべきことです。


1
「この他の質問が集めた担当者の意見と見解を見て、ほぼ同じ質問をして自分の質問を後押しすると思いました」という意味ではありませんでしたか?;-)
ボビージャック、

1
確かに、悲観論者。:)これをコミュニティの質問にすることを検討しました。また、一定数のポイントを獲得した後は、すべてリターンが減少します。
Allain Lalonde、

1
十分に公平です-担当者が「必要」であるようには見えません!私はC#に大きな問題があるだけだと思います-このサイトが意図されている種類の質問にはまったく似ていません。
ボビージャック

3
ええ、そうではないかもしれませんが、答えの知識は素晴らしいものでした。SOでなければ、平均的なC#プログラマーを1か所ですべてにさらすのは難しいと思う。同じハードウォンのリストを作成するには、何年も試してみる必要があります。
Allain Lalonde、

7
私はJavaScriptを専門的に10年以上作成しており、このスレッドから1つまたは3つのことを学びました。ありがとう、アラン!
Andrew Hedges

回答:


373

関数のパラメーターを定義する必要はありません。関数のarguments配列のようなオブジェクトを使用できます。

function sum() {
    var retval = 0;
    for (var i = 0, len = arguments.length; i < len; ++i) {
        retval += arguments[i];
    }
    return retval;
}

sum(1, 2, 3) // returns 6

117
ただし、引数は配列のように機能しますが、実際のJavaScript配列ではなく、単なるオブジェクトです。そのため、join()、pop()、push()、slice()などは実行できません。(必要に応じて、実際の配列に変換できます: "var argArray = Array.prototype.slice.call(arguments);")
Jacob Mattison

51
Argumentsオブジェクトへのアクセスは比較的コストがかかることにも注意してください-最良の例は、argumentsオブジェクトを参照するだけで関数の呼び出しが非常に遅くなるSafari、Firefox、およびChromeナイトリーです。if(false)引数; パフォーマンスが低下します。
olliej 2009

48
同じように、引数には現在の関数自体である「呼び出し先」プロパティがあります。これにより、匿名関数で再帰を実行できます。
ビンセントロバート

4
@Nathan "f(x、y、z)"は "f([x、y、z])"よりも良く見えます。
Mark Cidade

16
@Vincent Robert:arguments.callee廃止されることに注意してください。
ken

204

Douglas Crockfordの優れた著書であるJavaScript:The Good Partsのほとんどを引用できます 。

しかし、私は、あなたのためだけのものを取る常に使用します===と、!==代わりに==!=

alert('' == '0'); //false
alert(0 == ''); // true
alert(0 =='0'); // true

==推移的ではありません。使用===すると、期待どおりにこれらのステートメントすべてにfalseが与えられます。


29
多くの人がクロックフォードがすべてを知っていると思っているのは残念です。確かに、その人はほとんどの批判で的を射ていますが、私は多くの開発者がするように彼の作品に全面的な支持を与えることには至りません...
Jason Bunting

21
ジェイソンの警告の2番目。それ自体は本は非常に興味深いです、そして、それは良いアドバイスをたくさん与えていますが、DCがされてはるかにあまりにも物事の彼の方法は、唯一の正しい方法であることを確信し、他のすべては、「不良品」です。いくつかの例が必要な場合は、JSLint Yahoo Groupでの彼の回答をご覧ください。
Zilk、2008年

30
==の代わりに===を使用することは、動的型付けに混乱していて、「本当に」等しいことを望むだけの場合に良いアドバイスです。0 == ''または0 == '0'のように、動的型付けを理解している人は、キャストしたい状況で==を使い続ける場合があります。
thomasrutter 2009

20
まあ==と===は動的型付けについてではありません。==型強制を行いますが、これは別の獣です。string / number / etcにキャストすることがわかっている場合は、それを明示的に行う必要があります。
Rene Saarsoo、2009年

15
私が思う最も恐ろしい部分=='\n\t\r ' == 0=> true...:D
Shrikant Sharat

189

関数はJavaScriptの第一級市民です。

var passFunAndApply = function (fn,x,y,z) { return fn(x,y,z); };

var sum = function(x,y,z) {
  return x+y+z;
};

alert( passFunAndApply(sum,3,4,5) ); // 12

関数型プログラミング手法を使用して、エレガントなJavaScriptを記述できます

特に、関数はパラメーターとして渡すことができます。たとえば、Array.filter()はコールバックを受け入れます。

[1, 2, -1].filter(function(element, index, array) { return element > 0 });
// -> [1,2]

特定の関数のスコープ内にのみ存在する「プライベート」関数を宣言することもできます。

function PrintName() {
    var privateFunction = function() { return "Steve"; };
    return privateFunction();
}

3
JavaScriptで関数を作成する方法は3つあります。関数sum(x、y、z){return(x + y + z); }およびvar sum = new Function( "x"、 "y"、 "z"、 "return(x + y + z);"); 他の方法です。
マリウス

6
データとしての関数の概念は、私の本で間違いなく大きなポイントを獲得しています。
Jason Bunting

サンプルを更新して、特定の関数のスコープ内にのみ存在する「プライベート」関数の使用方法を示しました。
Chris Pietschmann、

new Function()と同じくらい悪evalです。使ってはいけません。
ニコラス

11
これが隠し機能かどうかはわかりません...コア機能のようです。
Claudiu

162

in演算子を使用して、オブジェクトにキーが存在するかどうかを確認できます。

var x = 1;
var y = 3;
var list = {0:0, 1:0, 2:0};
x in list; //true
y in list; //false
1 in list; //true
y in {3:0, 4:0, 5:0}; //true

オブジェクトリテラルが見苦しい場合は、パラメーターなしの関数ヒントと組み合わせることができます。

function list()
 { var x = {};
   for(var i=0; i < arguments.length; ++i) x[arguments[i]] = 0;
   return x
 }

 5 in list(1,2,3,4,5) //true

22
それほど賢くないので、値が存在するかどうかではなく、キーが存在するかどうかをチェックします。リスト内のx; x [1]!= nullのためにのみ機能し、値1が存在するためではありません。
Armin Ronacher、2009

1
私はこのテクニックを使用していなかったので、実際にオブジェクトリテラルを実際に使用したことを忘れていました。訂正ありがとうございます。
Mark Cidade、

34
また、注意してください:in演算子はプロトタイプチェーンもテストします!誰かがObject.prototypeに「5」と呼ばれるプロパティを配置した場合、2番目の例は「5 in list(1、2、3、4)」を呼び出した場合でもtrueを返します... hasOwnPropertyを使用する方がよいでしょうメソッド:list(1、2、3、4).hasOwnProperty(5)は、Object.prototypeにプロパティ '5'がある場合でもfalseを返します。
Martijn、

3
「hasOwnProperty」という名前が付けられている場合でも、オブジェクトに独自のプロパティがあるかどうかをテストできる非常に一般的なソリューションの場合は、Object.prototype.hasOwnProperty.call(object、name)にすべて移動する必要があります。 ;
クリスコワール

1
@Kris、誰かがObject.prototype.hasOwnPropertyを上書きしない限り、;)
Nick

153

変数へのデフォルト値の割り当て

||代入式で論理演算子または演算子を使用して、デフォルト値を提供できます。

var a = b || c;

a変数は、値の取得するc場合にのみbですfalsyを(ある場合はnullfalseundefined0empty string、またはNaN)、それ以外aの値を取得しますb

これは、関数が提供されていない場合に引数にデフォルト値を与えたいときに便利です。

function example(arg1) {
  arg1 || (arg1 = 'default value');
}

イベントハンドラーでのIEフォールバックの例:

function onClick(e) {
    e || (e = window.event);
}

次の言語機能は長い間使用されてきましたが、すべてのJavaScript実装でサポートされていますが、ECMAScript 5th Editionまでは仕様の一部ではありませんでした。

debugger声明

説明:§12.15デバッガーステートメント

このステートメントを使用すると、プログラムブレークポイントをプログラムに配置することができます。

// ...
debugger;
// ...

デバッガが存在するかアクティブな場合、その行でデバッガがすぐに中断します。

それ以外の場合、デバッガーが存在しないかアクティブでない場合、このステートメントは目に見える影響を及ぼしません。

複数行の文字列リテラル

記述:§7.8.4文字列リテラル

var str = "This is a \
really, really \
long line!";

の隣の文字は行末記号で\ なければならないため、注意が必要\です。たとえば、の後にスペースがある場合、コードはまったく同じに見えますが、が発生しますSyntaxError


28
nullの場合、falseと見なされた場合ではありません。a = 0 || 42; これは42になります。これはPythonやC#ではなく、?? オペレーター。C#の動作が必要な場合は、a =(b === null)を実行しますか?c:b;
Armin Ronacher、2009

ASP.NETで開発する場合、Visual Studioでも機能します:)
chakrit

2
||適切だったらいいのに|| 未定義の場合のみ。オーバーロードされたメソッドのエミュレーションを作成したかったので、最後の引数がオプションであり、代わりにデフォルト値が使用されるようにしたので、今日はこれに0で噛まれました。
egaga、

+1このトリックは、デフォルトのGoogleアナリティクススニペットで利用されています。`var _gaq = _gaq || []; `; 熱心なユーザーが自分の作業を上書きするのを防ぎます。
Yahel

2
複数行の文字列リテラル手法については知りませんでした。それは素晴らしいです、ありがとう。
チャーリーフラワーズ

145

JavaScriptにはブロックスコープがありません(ただし、クロージャーがあるので、それを呼び出しましょうか?)。

var x = 1;
{
   var x = 2;
}
alert(x); // outputs 2

3
それは良いことです。それはほとんどのCライクな言語とは本当に重要な違いです。
マーティンクラーク

9
「var tmp = function(){/ *ブロックスコープ* /}();」をいつでも実行できます。構文は醜いですが、動作します。
Joeri Sebrechts 2008

3
:それとも、それは、Firefoxのみだ場合、「せ」を使用することができますstackoverflow.com/questions/61088/...
ユージン横田

10
または単に:(function(){var x = 2;})(); alert(typeof x); // undefined
Pim Jager

@Pim:JSLintは次のように述べています:「呼び出しを関数を含む括弧に移動します。」「 'function'と '('の間にちょうど1つのスペースが必要です。」
Hello71

144

オブジェクトのプロパティにアクセスする[]代わりに.

これにより、変数に一致するプロパティを検索できます。

obj = {a:"test"};
var propname = "a";
var b = obj[propname];  // "test"

これを使用して、名前が有効な識別子ではないオブジェクトプロパティを取得/設定することもできます。

obj["class"] = "test";  // class is a reserved word; obj.class would be illegal.
obj["two words"] = "test2"; // using dot operator not possible with the space.

一部の人々はこれを知らず、このようにeval()を使用することになります

var propname = "a";
var a = eval("obj." + propname);

これは読みにくく、エラーを見つけるのが難しく(jslintを使用できません)、実行が遅く、XSSの悪用につながる可能性があります。


evalは悪ですが、まれにしか必要ありません
Doug Domeny

私はevalを決して使用せず、これを発見したときのことを覚えています。とても嬉しかったです。

要約すると、オブジェクトのプロパティにはドット表記と添え字表記の両方でアクセスできます
Russ Cam

9
興味深いことに、ドット参照は実際には、bracketrefの構文糖衣です。foo.barとにかく、仕様によると、のように動作しfoo["bar"]ます。また、すべてが文字列プロパティであることにも注意してください。配列アクセスを行う場合でもarray[4]、4は文字列に変換されます(これも、少なくともECMAScript v3仕様に従って)
Claudiu

私はすべてのJSプログラマーがこれを知っているべきだと思います。
Cem Kalyoncu

144

特定のトピックについて適切なJavaScript参照を探している場合は、クエリに「mdc」キーワードを含めると、最初の結果はMozilla Developer Centerから取得されます。私はオフラインでの参照や本を持ち歩きません。私は常に「mdc」キーワードトリックを使用して、探しているものに直接アクセスします。例えば:

Google:javascript array sort mdc
(ほとんどの場合、「javascript」を省略できます)

更新: Mozilla Developer CenterはMozilla Developer Networkに名前が変更されました。「mdc」キーワードトリックは引き続き機能しますが、すぐに代わりに「mdn」の使用開始しなければならない場合があります。


50
すばらしいリソースです。即座に、より良い安っぽいW3Schoolsのより...
DisgruntledGoat

11
Firefoxを使用している場合は、Googleにする必要さえありません。アドレスバーに「array mdc」と入力してEnterキーを押してください。
サーシャチェディゴフ2010

2
最良の部分は、このスタックオーバーフローの質問が結果の最初のページにどのように表示されるかです:)
Jiaaro 2010年

5
これに賛成:Googleの検索結果でMDCの結果をさらに引き上げる草の根のSEOイニシアチブ。
Yahel 2010

3
現在はMDNドキュメントセンターなので、 'mdc'キーワードは引き続き有効です:)
Aleadam

143

たぶん少し明白な人もいます...

Firebugをインストールし、console.log( "hello")を使用します。ランダムなalert();を使用するよりもはるかに優れています。これは、数年前によく行ったことです。


12
Firebugがインストールされていない可能性のある人にコードをリリースする前に、コンソールステートメントを削除することを忘れないでください。
Chris Noe、

161
function log(msg){if(console)console.log(msg)else alert(msg)}
Josh

4
さらに良いのは、ログステートメントの前に「;;;」を付けることです。そしてminifyはあなたのためにそれを処理します。(少なくとも、私が使用するPerlモジュールにはその機能があり、それが当たり前であると主張しています。)
Kev

10
Josh:コンソールが定義されていないので、それはうまくいきません。typeof console!== "undefined"またはwindow.consoleを確認できます。
イーライグレイ

23
常に含める:if(typeof( 'console')== 'undefined'){console = {log:function(){}}; その後、引き続きconsole.logを使用できますが、何も実行されません。
gregmac 2009

120

プライベートメソッド

オブジェクトはプライベートメソッドを持つことができます。

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;

    // A private method only visible from within this constructor
    function calcFullName() {
       return firstName + " " + lastName;    
    }

    // A public method available to everyone
    this.sayHello = function () {
        alert(calcFullName());
    }
}

//Usage:
var person1 = new Person("Bob", "Loblaw");
person1.sayHello();

// This fails since the method is not visible from this scope
alert(person1.calcFullName());

16
これは実際にはプライベート関数ではなく、ローカルスコープ内の関数変数です。
キース

6
本当ですが、すべての運用上の定義から、それは方法だと考えることができます。これは、インスタンスの状態にアクセスできる名前を持つコードのブロックであり、そのインスタンスでのみ表示できます。プライベートメソッドの定義は何ですか?
Allain Lalonde、

14
@ザック、まさに!クラスベースのオブジェクト指向言語を何年も使った後、オブジェクト指向の概念の1つの実装にすぎないことを忘れるのは簡単です。もちろん、準クラスベースのオブジェクト指向をJSに
詰め込も

5
疑問に思って、person1には法律ブログがありますか?;-)
トラビス

4
逮捕された開発リファレンスの+1
Domenic 2010

99

Crockfordの「Javascript:The Good Parts」でも言及されています。

parseInt()危険です。適切なベースを通知せずに文字列を渡すと、予期しない数値が返される場合があります。たとえばparseInt('010')、10ではなく8を返します。baseをparseIntに渡すと、正しく動作します。

parseInt('010') // returns 8! (in FF3)
parseInt('010', 10); // returns 10 because we've informed it which base to work with.

13
コードレビューを行うときは、常にこれを探してください。「、10」を除外することは、ほとんどのテストで気付かれない一般的な間違いです。
Doug Domeny 2009年

私は何年も前に基数の問題に火傷し、そのような直感に反する何かを忘れたことはありません。しばらく不思議に思うことになるので、指摘するのは素晴らしいことです。
JamesEggers

4
なぜ使用しMath.floorないのNumberですか?10 === Math.floor("010"); 10 === Number("010");floats:42 === Math.floor("42.69"); 42.69 === Number("42.69");
誰か

1
@Infinity投稿された回答がまだない場合は、そうする必要があります。組み込み関数の動作をオーバーライドするのがこれほど単純であるとは思いもしませんでした。もちろん、他のサイトから借りているコードパッケージをもう少し詳しく見る必要があります。その無害なparseInt機能は、それほど無害ではない何かを簡単に実行させることができます。
bob-the-destroyer

6
@Infinity:「コーディングエラー」を強調するためにfnを再定義するのはどうですか? __parseInt = parseInt; parseInt = function (str, base) { if (!base) throw new Error(69, "All your base belong to us"); return __parseInt(str, base); }
JBRウィルキンソン2010

97

関数はオブジェクトなので、プロパティを持つことができます。

fn = function(x){
   // ...
}

fn.foo = 1;

fn.next = function(y){
  //
}

13
これは非常に便利なヒントです。たとえば、関数のプロパティとしてデフォルト値を設定できます。例:myfunc.delay = 100; その後、ユーザーはデフォルト値を変更でき、すべての関数呼び出しは新しいデフォルト値を使用します。例:myfunc.delay = 200; myfunc();
BarelyFitz 2009年

便利です...そして危険です!
palswim 2010

ずさんに見えますが、なぜ変数の代わりにこれを使うのですか?
instantsetsuna 2010

1
@instantsetsuna:なぜ別の変数があるのですか?いつものように、これは「適切/有用なときに使用する」に
要約されます

91

自己実行関数といえばいいでしょう。

(function() { alert("hi there");})();

JavaScriptにはブロックスコープがないため、ローカル変数を定義する場合は、自己実行関数を使用できます。

(function() {
  var myvar = 2;
  alert(myvar);
})();

ここでmyvarは、isはグローバルスコープを妨害または汚染せず、関数が終了すると消えます。


2
これは何に役立ちますか?関数の外にアラートを配置しても同じ結果が得られます。
PotatoEngineer 2009年

7
それはアラートに関するものではなく、関数をすべて一度に定義して実行することに関するものです。その自己実行関数が値を返し、その関数をパラメーターとして別の関数に渡すことができます。
ScottKoon 2009年

5
@Paulカプセル化に適しています。
マイクロビンソン、

22
また、ブロックスコープにも適しています。
ジムハンジカー、

24
ええ、私はすべての.jsファイルを匿名の自己実行関数で囲み、その中でグローバルにアクセスできるようにしたいものをwindowオブジェクトに添付します。グローバルな名前空間の汚染を防ぎます。
cdmckay 2009年

83

関数が予期するパラメーターの数を知る

function add_nums(num1, num2, num3 ){
    return num1 + num2 + num3;
}
add_nums.length // 3 is the number of parameters expected.

関数が受け取るパラメーターの数を知る

function add_many_nums(){
    return arguments.length;
}    
add_many_nums(2,1,122,12,21,89); //returns 6

23
最初の部分を知りませんでした。いいね!
mcjabberz 2009

1
同様に、関数がを使用して予期している引数の数を確認できますfunction.length
シャビ

6
回答の最初の部分である
@Xavi

79

ここにいくつか興味深いものがあります:

  • NaN何でも(もNaN)と比較すると==<とを含めて常にfalse になり>ます。
  • NaN Not a Numberの略ですが、型を要求すると、実際には数値が返されます。
  • Array.sort コンパレーター関数を使用でき、クイックソートのようなドライバーによって呼び出されます(実装によって異なります)。
  • 正規表現「定数」は、最後に一致したもののように、状態を維持できます。
  • JavaScriptの一部のバージョンでは、アクセスにあなたをできるように$0$1$2正規表現のメンバー。
  • null他のものとは異なります。オブジェクトでも、ブール値でも、数値でも、文字列でも、でもありませんundefined。これは「代替」のようなものundefinedです。(注:typeof null == "object"
  • 最も外側のコンテキストでthisは、それ以外の場合は名前を付けることができない[Global]オブジェクトを生成します。
  • 変数のvar自動宣言だけに頼るのではなく、を使用して変数を宣言すると、ランタイムはその変数へのアクセスを最適化する本当のチャンスを得ることができます
  • withコンストラクトは、このようなoptimzationsを破壊します
  • 変数名にはUnicode文字を含めることができます。
  • JavaScriptの正規表現は実際には正規表現ではありません。これらはPerlの正規表現に基づいており、評価に非常に長い時間がかかる先読みを含む式を作成することが可能です。
  • ブロックにはラベルを付けて、のターゲットとして使用できますbreak。ループにラベルを付け、のターゲットとして使用できますcontinue
  • 配列はスパースではありません。それ以外の場合は空の配列の1000番目の要素を設定すると、で埋められるはずundefinedです。(実装による)
  • if (new Boolean(false)) {...}{...}ブロック を実行します
  • JavaScriptの正規表現エンジンは実装固有です。たとえば、「移植性のない」正規表現を作成することが可能です。

【良いコメントに応えて少し更新しました】コメントをご覧ください]


5
nullは実際には(特別な)オブジェクトです。typeof null「オブジェクト」を返します。
Ates Goral

4
[Global]オブジェクトは、次のような場所からも取得できます。var glb = function(){return this; }();
Zilk、2008年

2
ブラウザのJavaScriptのグローバルオブジェクトはウィンドウオブジェクトです。グローバルスコープの場合:window.a == a;
ピムイェーガー

8
「配列はスパースではない」は実装に依存します。a [1000]の値を設定してa [999]を見ると、そうですundefined。しかし、それは存在しないインデックスを探すときに取得するデフォルト値にすぎません。a [2000]をチェックした場合、それもになりますがundefined、メモリがまだ割り当てられているわけではありません。IE8では、JScriptエンジンがそのときどのように感じたかに応じて、一部の配列は密であり、一部は疎です。もっとここで読む:blogs.msdn.com/jscript/archive/2008/04/08/...
クリス・ニールセン

2
@Atesおよび@SF:typeofは、さまざまなタイプの「オブジェクト」を返します。しかし、それがどのように機能し、どのタイプが「オブジェクト」として識別されるかを知っていれば、その実装は少なくとも信頼性があり、一貫しています。
thomasrutter 2010年

77

私はパーティーに遅れていることは知っていますが、+オペレーターの有用性が「何かを数値に変換する」以上に言及されていないことを信じられません。多分それはそれがどれほどうまく機能を隠しているのですか?

// Quick hex to dec conversion:
+"0xFF";              // -> 255

// Get a timestamp for now, the equivalent of `new Date().getTime()`:
+new Date();

// Safer parsing than parseFloat()/parseInt()
parseInt("1,000");    // -> 1, not 1000
+"1,000";             // -> NaN, much better for testing user input
parseInt("010");      // -> 8, because of the octal literal prefix
+"010";               // -> 10, `Number()` doesn't parse octal literals 

// A use case for this would be rare, but still useful in cases
// for shortening something like if (someVar === null) someVar = 0;
+null;                // -> 0;

// Boolean to integer
+true;                // -> 1;
+false;               // -> 0;

// Other useful tidbits:
+"1e10";              // -> 10000000000
+"1e-4";              // -> 0.0001
+"-12";               // -> -12

もちろん、Number()代わりにこれを使用してこれらすべてを行うことができますが、+演算子はとてもきれいです!

プロトタイプのvalueOf()メソッドをオーバーライドして、オブジェクトの数値の戻り値を定義することもできます。そのオブジェクトで実行される数値変換はNaN、ではなく、valueOf()メソッドの戻り値になります。

var rnd = {
    "valueOf": function () { return Math.floor(Math.random()*1000); }
};
+rnd;               // -> 442;
+rnd;               // -> 727;
+rnd;               // -> 718;

簡単にできます、0xFFなど必要ありません+"0xFF"
nyuszika7h

9
@ Nyuszika7H:他のプリミティブとオブジェクト数値に強制しているという点が不足しています。もちろん0xFF1代わりに書くことができるのと同じように、単に書くことができます+true。必要に応じて+("0x"+somevar)、の代替として使用できることをお勧めしますparseInt(somevar, 16)
アンディE

75

" JavaScriptの拡張メソッド "は、prototypeプロパティを介して。

Array.prototype.contains = function(value) {  
    for (var i = 0; i < this.length; i++) {  
        if (this[i] == value) return true;  
    }  
    return false;  
}

これにより、containsすべてのArrayオブジェクトにメソッドが追加されます。この構文を使用してこのメ​​ソッドを呼び出すことができます

var stringArray = ["foo", "bar", "foobar"];
stringArray.contains("foobar");

18
他のコード(あなたのものではない)がArrayオブジェクトについて仮定している可能性があるため、これは一般に悪い考えと見なされます。
Chris Noe、

39
また、一般に、Arrayオブジェクトについて想定することは悪い考えです。:(
まぶたがない2008年

Uhmmmm .. javascript 1.6 array extras?の指標?ベルを鳴らしていますか?
ブルトン語

2
@Breton:これはArrayクラスに固有のものではなく、単なる例です。これを使用して、新しいDate()。toString();を拡張します。メソッド、マスク文字列の使用を許可します。任意のオブジェクトを拡張でき、そのすべてのインスタンスが新しいメソッドを取得します。
EstebanKüber2009年

1
@Mathias:これはDOMに関するものではありません。
ドルメン

60

オブジェクトからプロパティを適切に削除するには、単にundefinedに設定するのではなく、プロパティを削除する必要があります。

var obj = { prop1: 42, prop2: 43 };

obj.prop2 = undefined;

for (var key in obj) {
    ...

プロパティprop2は引き続き反復の一部になります。prop2を完全に削除したい場合は、代わりに次のようにする必要があります。

delete obj.prop2;

プロパティprop2は、プロパティを反復処理しているときに表示されなくなります。


3
deleteステートメントには、ブラウザ固有の癖がないわけではないことに注意してください。たとえば、IEで試してみて、オブジェクトがネイティブJSオブジェクトでない場合(自分で追加したプロパティを削除する場合でも)、これは大きなエラーで失敗します。また、delete myvarのように、変数を削除することもできません。しかし、私はそれがいくつかのブラウザでうまくいくと思います。上記の回答のコードはかなり安全ですが。
thomasrutter

ちなみに、undefinedも変数にすることができます!var undefined = "something"をお試しください
ヨハンフィリップストラトハウゼン

57

with

それはめったに使用されず、率直に言って、ほとんど使用されません...しかし、限られた状況では、それはその用途があります。

たとえば、オブジェクトリテラルは、新しいオブジェクトのプロパティをすばやく設定するのに非常に便利です。しかし、既存のオブジェクトのプロパティの半分を変更する必要がある場合はどうでしょうか。

var user = 
{
   fname: 'Rocket', 
   mname: 'Aloysus',
   lname: 'Squirrel', 
   city: 'Fresno', 
   state: 'California'
};

// ...

with (user)
{
   mname = 'J';
   city = 'Frostbite Falls';
   state = 'Minnesota';
}

コンテキストとして使用されるオブジェクトがない場合:アラン・ストームは、これは多少危険とすることができることを指摘有しに割り当てられた特性のいずれかを、それがおそらくグローバル変数を作成または上書きし、外側のスコープで解決されるであろう。これは、デフォルト値または空の値を持つプロパティが未定義のままになっているオブジェクトを操作するコードの記述に慣れている場合は特に危険です。

var user = 
{
   fname: "John",
// mname definition skipped - no middle name
   lname: "Doe"
};

with (user)
{
   mname = "Q"; // creates / modifies global variable "mname"
}

したがって、そのwithような割り当てにはステートメントを使用しないことをお勧めします。

参照:JavaScriptの「with」ステートメントの正当な用途はありますか?


29
慣習的なwith with文は避けられます。ユーザーオブジェクトに指定したプロパティのいずれかがない場合、withブロックの疑似スコープの外側の変数が変更されます。その方法にはバグがあります。詳細については、yuiblog.com / blog / 2006/04/11 / with
Alan Storm

1
異論は、スペルミスの変数に関するものではなく、コードのブロックを見て、そのブロック内の特定の行が何を行うかを確実に言えるようにすることです。JavaScriptオブジェクトは非常に動的であるため、現時点でそれがどのようなプロパティ/メンバーを持っているかを明確に述べることはできません。
アランストーム

2
アーメン-私が見つけたJSで「with」ステートメントを見た場合、それを排除し、それを書いた開発者に、なぜそれを使用するのが良いことではないのかを知っているかどうか質問します...「非表示の機能」「忌まわしい機能」に似ています。
Jason Bunting

1
より複雑なチェーンabcd "with(abc){d.foo = bar;}は強力であり、本質的にエラーが発生しにくいと考えてください。ルートは、ルートを1レベル上げることです。そして、変数名のスペルを間違えていますか?バグを導入しています「with」に関係なく、どこにいて
annakata 2009年

4
Douglas Crockfordは最近、「with」は.NET RocksのJavaScriptの最悪の部分の1つだと言っています。ポッドキャスト。
コア

51

メソッド(または関数)は、操作対象として設計されたタイプではないオブジェクトで呼び出すことができます。これは、カスタムオブジェクトでネイティブ(高速)メソッドを呼び出すのに最適です。

var listNodes = document.getElementsByTagName('a');
listNodes.sort(function(a, b){ ... });

このコードlistNodesは、Array

Array.prototype.sort.apply(listNodes, [function(a, b){ ... }]);

が使用listNodesするのに十分な配列のようなプロパティ(長さ、[]演算子)を定義しているため、このコードは機能しsort()ます。


43

プロトタイプの継承(Douglas Crockfordによって普及)は、Javascriptの負荷について考える方法に革命をもたらします。

Object.beget = (function(Function){
    return function(Object){
        Function.prototype = Object;
        return new Function;
    }
})(function(){});

それはキラーです!残念ながら、ほとんど誰もそれを使用していません。

他のプロパティへの(ライブの)プロトタイプ継承リンクを維持しながら、任意のオブジェクトの新しいインスタンスを「取得」して拡張できます。例:

var A = {
  foo : 'greetings'
};  
var B = Object.beget(A);

alert(B.foo);     // 'greetings'

// changes and additionns to A are reflected in B
A.foo = 'hello';
alert(B.foo);     // 'hello'

A.bar = 'world';
alert(B.bar);     // 'world'


// ...but not the other way around
B.foo = 'wazzap';
alert(A.foo);     // 'hello'

B.bar = 'universe';
alert(A.bar);     // 'world'

42

これを好みの問題と呼ぶ人もいますが、

aWizz = wizz || "default";
// same as: if (wizz) { aWizz = wizz; } else { aWizz = "default"; }

三項演算子はチェーン化して、Schemeの(cond ...)のように動作させることができます。

(cond (predicate  (action  ...))
      (predicate2 (action2 ...))
      (#t         default ))

次のように書くことができます...

predicate  ? action( ... ) :
predicate2 ? action2( ... ) :
             default;

これは、副作用なしでコードを分岐させるため、非常に「機能的」です。だから代わりに:

if (predicate) {
  foo = "one";
} else if (predicate2) {
  foo = "two";
} else {
  foo = "default";
}

あなたは書ける:

foo = predicate  ? "one" :
      predicate2 ? "two" :
                   "default";

再帰でもうまくいきます:)


私はあなたが与える述語構文が好きです。私はそのような連鎖を考えたことがありません。きちんとした。
Allain Lalonde、

2
ええと... JavaScriptにはswitch()ステートメントがあります。:-)
staticsan

私はswitchステートメントの大ファンではありません-それらはCのアーティファクトであり、関数型プログラミングではありません。私の例では、switchステートメントには3つの個別のステートメントが必要であり、すべて "foo ="で始まります-明らかに不必要な繰り返しです。
Andrey Fedorov、

14
一例として、三項演算子を歓迎します。
thomasrutter

8
もう一度読んで、これは「コードを別の言語のように見せること」ではなく、実際にはコードのセマンティックな意味を単純化することを指摘したいと思います。これは、「if」ではなく「foo = ...」で始まるステートメントです。
Andrey Fedorov

41

数字もオブジェクトです。だからあなたは次のようなクールなことをすることができます:

// convert to base 2
(5).toString(2) // returns "101"

// provide built in iteration
Number.prototype.times = function(funct){
  if(typeof funct === 'function') {
    for(var i = 0;i < Math.floor(this);i++) {
      funct(i);
    }
  }
  return this;
}


(5).times(function(i){
  string += i+" ";
});
// string now equals "0 1 2 3 4 "

var x = 1000;

x.times(function(i){
  document.body.innerHTML += '<p>paragraph #'+i+'</p>';
});
// adds 1000 parapraphs to the document

ああ、神様!toString(radix)について知りませんでした...
Ates Goral

1
その実装timesは効率的ではありませんMath.floor。一度だけではなく、毎回呼び出されます。
ドルメン

33

JavaScriptのクロージャーはどうですか(C#v2.0 +の無名メソッドと同様)。関数または「式」を作成する関数を作成できます。

閉鎖の例:

//Takes a function that filters numbers and calls the function on 
//it to build up a list of numbers that satisfy the function.
function filter(filterFunction, numbers)
{
  var filteredNumbers = [];

  for (var index = 0; index < numbers.length; index++)
  {
    if (filterFunction(numbers[index]) == true)
    {
      filteredNumbers.push(numbers[index]);
    }
  }
  return filteredNumbers;
}

//Creates a function (closure) that will remember the value "lowerBound" 
//that gets passed in and keep a copy of it.
function buildGreaterThanFunction(lowerBound)
{
  return function (numberToCheck) {
    return (numberToCheck > lowerBound) ? true : false;
  };
}

var numbers = [1, 15, 20, 4, 11, 9, 77, 102, 6];

var greaterThan7 = buildGreaterThanFunction(7);
var greaterThan15 = buildGreaterThanFunction(15);

numbers = filter(greaterThan7, numbers);
alert('Greater Than 7: ' + numbers);

numbers = filter(greaterThan15, numbers);
alert('Greater Than 15: ' + numbers);

1
よくわかりませんが、(numberToCheck> lowerBound)を返すことができますか?真/偽; 単にreturnになる(numberToCheck> lowerBound); ちょうど私の理解を高めるためにしようと...
davidsleeps

4
C#の無名関数はクロージャーと同等であり、その逆ではありません:)
vava

11
クロージャーと無名関数は、別個の異なる概念です。名前を付けなくても作成できる関数は、無名関数です。「creating」スコープの変数が作成された関数にリンクされていることはクロージャーです。つまり、クロージャーは隠されたグローバル変数に似ています。
slebetman、2010年

1
それは本当だ。無名メソッドが作成スコープの変数を使用する場合のみ、クロージャに似ています。答えの英語を更新しました。それでもまだ望ましいことはありませんが、正しい英語に迷っています。
タイラー

2
これは、クロージャーが何であるかの例を理解するのに最適または最も簡単ではないと思います。ただ言って。クロージャーのポイントは、一連の変数が「スコープから外れた」ように見える場合でも、そのスコープ内で最初に定義された関数で引き続き使用できるということです。上記の例では、外側の関数buildGreaterThanFunctionが終了しても、lowerBound変数は内側の匿名関数から引き続きアクセスできます。
thomasrutter

32

また、言及したプロトタイプチェーンspoon16を使用して、クラスを拡張(継承)し、プロパティ/メソッドオーバーライドすることもできます

次の例では、Petクラスを作成し、いくつかのプロパティを定義します。Objectから継承した.toString()メソッドもオーバーライドします。

この後、Pet拡張して.toString()メソッドをオーバーライドするDogクラスを作成し、再度その動作(多態性)を変更します。さらに、他のいくつかのプロパティを子クラスに追加します。

この後、継承チェーンをチェックして、DogがまだDog型、Pet型、Object型であることを示します。

// Defines a Pet class constructor 
function Pet(name) 
{
    this.getName = function() { return name; };
    this.setName = function(newName) { name = newName; };
}

// Adds the Pet.toString() function for all Pet objects
Pet.prototype.toString = function() 
{
    return 'This pets name is: ' + this.getName();
};
// end of class Pet

// Define Dog class constructor (Dog : Pet) 
function Dog(name, breed) 
{
    // think Dog : base(name) 
    Pet.call(this, name);
    this.getBreed = function() { return breed; };
}

// this makes Dog.prototype inherit from Pet.prototype
Dog.prototype = new Pet();

// Currently Pet.prototype.constructor
// points to Pet. We want our Dog instances'
// constructor to point to Dog.
Dog.prototype.constructor = Dog;

// Now we override Pet.prototype.toString
Dog.prototype.toString = function() 
{
    return 'This dogs name is: ' + this.getName() + 
        ', and its breed is: ' + this.getBreed();
};
// end of class Dog

var parrotty = new Pet('Parrotty the Parrot');
var dog = new Dog('Buddy', 'Great Dane');
// test the new toString()
alert(parrotty);
alert(dog);

// Testing instanceof (similar to the `is` operator)
alert('Is dog instance of Dog? ' + (dog instanceof Dog)); //true
alert('Is dog instance of Pet? ' + (dog instanceof Pet)); //true
alert('Is dog instance of Object? ' + (dog instanceof Object)); //true

この質問に対する両方の回答は、Ray DjajadinataによるすばらしいMSDN記事から修正されたコードでした。


31

タイプによっては、例外をキャッチする場合があります。MDCから引用:

try {
   myroutine(); // may throw three exceptions
} catch (e if e instanceof TypeError) {
   // statements to handle TypeError exceptions
} catch (e if e instanceof RangeError) {
   // statements to handle RangeError exceptions
} catch (e if e instanceof EvalError) {
   // statements to handle EvalError exceptions
} catch (e) {
   // statements to handle any unspecified exceptions
   logMyErrors(e); // pass exception object to error handler
}

注:条件付きcatch句は、Netscape(およびMozilla / Firefox)の拡張であり、ECMAScript仕様の一部ではないため、特定のブラウザ以外では信頼できません。


29
私はそれを助けることができなかった:キャッチ(私youCan場合)
ATES Goral

6
引用したMDCページのメモをお読みください。条件付きキャッチ句は、Netscape(およびMozilla / Firefox)の拡張機能であり、ECMAScript仕様の一部ではないため、特定のブラウザー以外では信頼できません。
Jason S

31

頭の上から...

関数

arguments.calleeは「arguments」変数をホストする関数を参照するため、無名関数を再帰するために使用できます。

var recurse = function() {
  if (condition) arguments.callee(); //calls recurse() again
}

これは、次のようなことをしたい場合に便利です。

//do something to all array items within an array recursively
myArray.forEach(function(item) {
  if (item instanceof Array) item.forEach(arguments.callee)
  else {/*...*/}
})

オブジェクト

オブジェクトメンバーの興味深い点:名前として任意の文字列を使用できます。

//these are normal object members
var obj = {
  a : function() {},
  b : function() {}
}
//but we can do this too
var rules = {
  ".layout .widget" : function(element) {},
  "a[href]" : function(element) {}
}
/* 
this snippet searches the page for elements that
match the CSS selectors and applies the respective function to them:
*/
for (var item in rules) {
  var elements = document.querySelectorAll(rules[item]);
  for (var e, i = 0; e = elements[i++];) rules[item](e);
}

文字列

String.splitは、パラメータとして正規表現を使用できます。

"hello world   with  spaces".split(/\s+/g);
//returns an array: ["hello", "world", "with", "spaces"]

String.replaceは、検索パラメーターとして正規表現を、置換パラメーターとして関数を使用できます。

var i = 1;
"foo bar baz ".replace(/\s+/g, function() {return i++});
//returns "foo1bar2baz3"

あなたが言及すること...それらはすべてのブラウザに実装されていますか?
cllpse 2008

4
いいえ。Mosaicにはそれらのほとんどが欠けていると思います。
jsight 2008年

2
JavaScript機能は、そうです、それらはすべての主要なブラウザー(IE6 / 7、FF2 / 3、Opera 9 +、Safari2 / 3およびChrome)に実装されています。document.querySelectorAllはまだすべてのブラウザーでサポートされていません(これはJQueryの$()のW3Cバージョンであり、プロトタイプの$$()です)
Leo

6
arguments.callee廃止されており、ECMAScriptの5に投げると例外う
Hello71

まったくそうではありません。オブジェクトキーでは、文字列 "hasOwnProperty"を名前として使用できません(組み込みオブジェクトメソッドをオーバーライドするため)。
ブルトン

29

ほとんどの場合、スイッチの代わりにオブジェクトを使用できます。

function getInnerText(o){
    return o === null? null : {
        string: o,
        array: o.map(getInnerText).join(""),
        object:getInnerText(o["childNodes"])
    }[typeis(o)];
}

更新:事前に評価するケースが非効率的であることが心配な場合(なぜ、プログラムの設計の早い段階で効率を心配しているのですか?)、次のようなことができます。

function getInnerText(o){
    return o === null? null : {
        string: function() { return o;},
        array: function() { return o.map(getInnerText).join(""); },
        object: function () { return getInnerText(o["childNodes"]; ) }
    }[typeis(o)]();
}

これは、スイッチやオブジェクトよりも入力(または読み取り)の負担が大きくなりますが、スイッチの代わりにオブジェクトを使用する利点が保持されます。詳細については、以下のコメントセクションを参照してください。このスタイルはまた、十分に大きくなれば、これを適切な「クラス」にスピンアウトすることをより簡単にします。

update2:ES.nextに提案された構文拡張により、これは

let getInnerText = o -> ({
    string: o -> o,
    array: o -> o.map(getInnerText).join(""),
    object: o -> getInnerText(o["childNodes"])
}[ typeis o ] || (->null) )(o);

3
このようにして、Pythonはswitchステートメントなしで成功します。
outis 09/07/23

2
問題は、常にすべてのケースを評価することです。
Kornel、2011年

@porneLこれは真実ですが、いくつかの利点があります:論理的にクリーンです:ケースはハッシュテーブルで検索される文字列であり、真が返されるまでそれぞれが等しいかどうかを評価する必要がある式ではありません。したがって、評価される「値」は増えますが、評価される「キー」は少なくなります。オブジェクトは動的に生成し、後のスケーラビリティに合わせて変更したり、UIの印刷やドキュメントの生成に反映したり、動的な「ルックアップ」関数に置き換えたりすることができます。これは、コピー/貼り付けのケースよりも優れています。ブレーク、フォールスルー、またはデフォルト値についての混乱はありません。JSONでシリアル化できます...
ブルトン

@porneLああそうです。スケーラビリティについても、オブジェクトは外部設定またはデータファイルに簡単にスピンアウトすることができます。switchステートメントよりもやや簡単な変更ですが、最初にオブジェクトを念頭に置いて設計されている場合は簡単ですと。
ブルトン語

私はこれが遅いエントリであることを知っていますが、カスタム型チェックロジックがない限り、配列がいつあなたの例で機能するのですか?var arr = []; typeof arr; // object
keeganwatkins、2011年

25

オブジェクトのプロパティを反復処理するときは、必ずhasOwnPropertyメソッドを使用してください。

for (p in anObject) {
    if (anObject.hasOwnProperty(p)) {
        //Do stuff with p here
    }
}

これはanObject直接プロパティにのみアクセスし、プロトタイプチェーンの下にあるプロパティを使用しないようにするために行われます。


23

パブリックインターフェイスを持つプライベート変数

これは、自己呼び出し関数の定義とともに、きちんとした小さなトリックを使用しています。返されるオブジェクト内のすべてはパブリックインターフェイスで使用できますが、その他はすべてプライベートです。

var test = function () {
    //private members
    var x = 1;
    var y = function () {
        return x * 2;
    };
    //public interface
    return {
        setx : function (newx) {
            x = newx;
        },
        gety : function () {
            return y();
        }
    }
}();

assert(undefined == test.x);
assert(undefined == test.y);
assert(2 == test.gety());
test.setx(5);
assert(10 == test.gety());

1
これはモジュールパターンと呼ばれ、yuiblog.com / blog / 2007/06/12 / module-patternでEric Miragliaによって吹き替えられまし た。名前は誤解を招くと思いますが、シングルトンパターンなどと呼ばれるべきです。また、パブリックメソッドが「this」オブジェクトを使用して他のパブリックメソッドを呼び出すこともできることも付け加えておきます。私はコードで常にこのパターンを使用して、物事を整理し、きれいに保ちます。
mikeycgto 2009
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.