Javascriptの概要

私は.NET開発者です。 しかし最近、私はJavaScriptに出くわします。 さらに、ケースの50%で、残りの50件で何かを書いています-他の誰かのコードを処理し、さらにミニフィケーション、時には難読化を通過しました。 この記事では、言語を理解し、効果的に作業するために私にとって重要だと思われるポイントを共有したかったのです。 すでにその言語を扱った人々にとって新しいものや未知のものはなく、他の情報源で見つけることができないものはありません。 私にとって、この記事は、私の知識をリフレッシュする機会として、読者にとって主題をよりよく理解する方法として役立つでしょう。



Brendan Ikeは、JavaScriptは10日間で作成されたと述べました。 このアイディアはもっと長くなってきたと思います。 それがそうであるかもしれないが、言語は判明し、それ以来人気を獲得している。 特にAJAXの登場後。



JavaScriptは、弱い動的な暗黙的な型指定、自動メモリ管理、およびプロトタイプ継承を備えた言語です。



JavaScriptは、3つの異なる部分で構成されています。







この記事では主にコアについて説明します。 もちろん、コード例ではDOM要素とBOM要素が使用されますが、それらに焦点を合わせることはしません。



型システム



JavaScriptタイプ図は次のようになります。







およそ-この図には含まれていないエラーのタイプがまだあるため。



これらのうち、5つのタイプがプリミティブです。







それ以外はすべてオブジェクトです。 ブール、ストリング、および数値プリミティブは、対応するオブジェクトにラップできます。 この場合、オブジェクトはそれぞれブール、ストリング、および数値コンストラクターのインスタンスになります。



console.log('Holly Golightly' == new String('Holly Golightly')); // true console.log('Holly Golightly' === new String('Holly Golightly')); // false console.log('Holly Golightly' === String('Holly Golightly')); // true
      
      







プリミティブにはプロパティがありません。 たとえば、Stringプリミティブのlengthプロパティの値を取得しようとすると、プリミティブはオブジェクトに変換され、プロパティはプロパティの値を取得した後、ガベージコレクターのどこかに移動します。



プリミティブはプロパティを追加できません。



 var person = 'Paul Varjak'; person.profession = 'writer'; console.log(person.profession); // undefined
      
      







どうした 原始人はオブジェクトに変換され、プロパティがオブジェクトに追加された後、忘却になりました。



数字



JavaScriptの数値は、数値型で表されます。言語では、整数、固定小数点数、浮動小数点数への分割はありません。 分数の演算は必ずしも正確ではないことを忘れないでください。 例えば



 console.log(0.1 + 0.2); // 0.30000000000000004 console.log(0.2 + 0.3); // 0.5
      
      







Number型の言語には、いくつかの特別な意味があります:+ Infinity、-Infinity、およびNaN。



 console.log(Infinity === Infinity) // true
      
      







そして今、注意



 console.log(NaN === NaN); // false
      
      







NaNはまったく等しくありません。 NaNをチェックする場合、isNaN関数が言語に組み込まれています。 そうそう、Finite関数もあります。 NaNは伝染性です。NaNを使用したMathの算術演算または関数の結果もNaNです。 しかし、<<、>>、>>>、||、|、^、&、! (算術演算以上のものがあります)NaNは破壊できます。



 console.log(NaN || 2); // 2 console.log(0 || NaN); // NaN console.log(!NaN); // true
      
      







parseInt関数には注意する必要があります。古いブラウザと新しいブラウザでは、文字列を最初から処理するときの動作が異なります。 そして、常に番号体系を示すことをお勧めします。 古いブラウザは、先頭のゼロを8進数の記号として認識します。





JavaScriptの文字列は、Unicode文字のシーケンスにすぎません。 単一の文字に個別のタイプはなく、代わりに長さ1のストリングが使用されます。



JavaScriptの文字列は不変です。 つまり、作成後に行を変更することはできず、行に対するすべての操作で新しいオブジェクトが作成されます。 関数への引数としての文字列は、値ではなく参照によって渡されます。 ただし、同じ行が異なる方法で処理された場合でも、行は不変であるため、コードは予測どおりに動作します。



最初のパラメータが正規表現ではなく文字列を受け取る場合、replace関数は文字列内の最初の部分文字列のみを置換することを忘れないでください。 さらに、正規表現はグローバルである必要があります(g修飾子が必要です)。



 var str = "This is the house that Jack built. This is the malt That lay in the house that Jack built. This is the rat, That ate the malt That lay in the house that Jack built".replace("Jack", "Captain Jack Sparrow"); console.log(str); // This is the house that Captain Jack Sparrow built. This is the malt That lay in the house that Jack built. This is the rat, That ate the malt That lay in the house that Jack built var str = "This is the house that Jack built. This is the malt That lay in the house that Jack built. This is the rat, That ate the malt That lay in the house that Jack built".replace(/Jack/, "Captain Jack Sparrow"); console.log(str); // This is the house that Captain Jack Sparrow built. This is the malt That lay in the house that Jack built. This is the rat, That ate the malt That lay in the house that Jack built var str = "This is the house that Jack built. This is the malt That lay in the house that Jack built. This is the rat, That ate the malt That lay in the house that Jack built".replace(/Jack/g, "Captain Jack Sparrow"); console.log(str); // This is the house that Captain Jack Sparrow built. This is the malt That lay in the house that Captain Jack Sparrow built. This is the rat, That ate the malt That lay in the house that Captain Jack Sparrow built
      
      







ところで、コールバック関数も渡すことができます。 以下の例は、自転車の開発からあなたを救うことができます。



 var callback = (function(i){ return function(a){ i++; return a + i; }; })(0); var str = "This is the house that Jack built. This is the malt That lay in the house that Jack built. This is the rat, That ate the malt That lay in the house that Jack built".replace(/Jack/g, callback); console.log(str); // This is the house that Jack1 built. This is the malt That lay in the house that Jack2 built. This is the rat, That ate the malt That lay in the house that Jack3 built
      
      







正規表現は状態を保存し、testメソッドとexecメソッドの結果は引数と状態の両方に依存することを覚えておくことが重要です。 以下にいくつかの例を示します(ありがとう、 sekrasoft ):



 /a/g.test('aa') // true /a/g.test('ab') // true var re = /a/; re.test('aa') // true re.test('ab') // true //  var re = /a/g; re.test('aa') // true re.lastIndex // 1,  'aa'    a,     re.test('ab') // false re.lastIndex // 0, ..    re.test('ab') // true re.lastIndex // 1
      
      







キリル文字列は、localeCompare関数と最もよく比較されます。



 "" > "" // false "" > "" // true "".localeCompare("") // 1 "".localeCompare("") // 1
      
      







時期尚早の最適化は悪です。 次に例を示します。



jsperf.com/array-join-vs-connect



 //  1 var arr = []; for (var i = 0; i < 10000; i++) { arr.push(i); } var result = arr.join(', ') //  2 var result = ''; for (var i = 0; i < 9999; i++) { result += i + ', '; } result += i;
      
      







2番目のオプションは、パフォーマンスで勝ちます。



jsperf.com/heera-string-literal-vs-object



 //  1 var s = '0123456789'; for (var i = 0; i < s.length; i++) { s.charAt(i); } //  2 var s = new String('0123456789'); for (var i = 0; i < s.length; i++) { s.charAt(i); }
      
      







この場合、最初のオプションが大きなマージンで勝ちます。 実際、ブラウザエンジンには、このようなテンプレートの最適化が既に統合されています。



二重引用符と単一引用符の両方を使用して、文字列を構成できます。 JSONは二重引用符でのみ有効です。 残りは、プロジェクトで採用されているスタイルに従うことです。



nullおよび未定義



nullおよびundefinedは、対応するオブジェクトを持たないプリミティブです。 したがって、文字列、数値、ブール値とは異なり、これらのプリミティブの1つにプロパティを追加しようとしたり、プロパティ値を取得しようとすると、TypeErrorが発生します。

意味的にnullとundefinedは似ていますが、違いがあります。 nullはオブジェクトがないことを意味し、undefinedはそのような値がないことを意味します。 nullはキーワード、undefinedはグローバルコンテキストプロパティです。 確かに、最新のブラウザでは、異なる値を割り当てても機能しません。 未割り当ての変数はデフォルトで未定義になります。



オブジェクト



JavaScriptのオブジェクトは連想配列です。



空のオブジェクトはいくつかの方法で作成できます。



 var obj = {}; var obj1 = new Object(); var obj2 = Object.create(null);
      
      







最初のメソッドはリテラルと呼ばれ、使用することをお勧めします。



コンストラクター関数を使用してオブジェクトを作成することもできます。



 function Company(name, address){ this.name = name; this.address = address; } var company = new Company('Sing-Sing', 'Ossining, Westchester County, New York, United States');
      
      







作成されたオブジェクトのプロパティにアクセスするには、主に2つの方法があります。



 obj.name = 'Tiffany' var name = obj.name;
      
      







そして



 obj['name'] = 'Tiffany'; var name = obj['name'];
      
      







JavaScriptオブジェクトのキーは常に文字列であるため、任意のキーを持つ辞書として使用することはできません。 キーとして文字列以外を使用しようとすると、使用される値が文字列にキャストされます。



 var obj = {}; obj[1] = 1; obj[null] = 2; obj[{}] = 3; obj[{a: 1}] = 4; var val = obj[{}] // 4 Object.getOwnPropertyNames(obj); // ["1", "null", "[object Object]"]
      
      







{}と{a:1}が同じ値-"[object Object]"にキャストされ、数値とnullが対応する行に変換されたことがわかります。



この言語には、ゲッターとセッターを使用してプロパティを作成する機能があります。 これを行うにはいくつかの方法があります。



リテラル:



 var consts = { get pi(){ return 3.141592; }, set pi(){ throw new Error('Property is read only'); } };
      
      







Object.defineProperty関数の使用:



 var consts = {}; Object.defineProperty(consts, 'pi', { get : function () { return 3.14159265359; }, set: function(){ throw new Error('Property is read only'); } });
      
      







Object.defineProperties関数を使用する:



 var consts = {}; Object.defineProperties(consts, {'pi': { get : function () { return 3.14159265359; }, set: function(){ throw new Error('Property is read only'); }}, 'e': { get : function () { return 2.71828182846; }, set: function(){ throw new Error('Property is read only'); } }});
      
      







機能



JavaScriptでは、関数は組み込みのFunctionクラスのオブジェクトです。 これらは変数に割り当てられ、関数にパラメーターとして渡され、関数の結果として返され、それらのプロパティにアクセスできます。



関数の名前は次のとおりです。



 function getAnswer(){ return 42; }
      
      







および匿名:



 var getAnswer = function(){ return 42; }
      
      







関数には、好きなだけパラメーターを渡すことができます。 それらはすべて、引数オブジェクトを介して利用できます。 さらに、このオブジェクトには、長さプロパティ(引数と呼び出し先の数)、関数自体へのリンクがあります。



 function toArray(){ return Array.prototype.slice.call(arguments); } toArray(1, 2, 3, 6, 'Tiffany'); // [1, 2, 3, 6, "Tiffany"]
      
      







関数自体へのリンクにより、再帰的な匿名関数を作成できます。



 var fibonacci = function(n){ if (n <= 1){ return n; } else { return arguments.callee(n - 2) + arguments.callee(n - 1); } } console.log(fibonacci(22)); // 17711
      
      







標準の最新版では、このプロパティは削除されました。 しかし、次のように書くことができます:



 var fibonacci = function f(n){ if (n <= 1){ return n; } else { return f(n - 2) + f(n - 1); } } console.log(fibonacci(22)); // 17711
      
      







JavaScriptでvarを介して宣言された変数のスコープは、関数によって制限されます。 letキーワードは準備中ですが、ブロックスコープを設定しますが、ブラウザーはしぶしぶサポートします。



よくやる。 これは、自己実行関数またはすぐに呼び出される関数式と呼ばれます。



 (function(){ var person = new Person(); // do something })();
      
      







これは良い習慣だと思います。 したがって、不必要な変数でグローバルスコープを詰まらせないことがわかります。



このキーワード



JavaScriptでのこの値は、関数が作成されるオブジェクトに依存しません。 通話中に決定されます。



グローバルなコンテキストで:



 console.log(this); // Window
      
      







オブジェクトのプロパティとして:



 var obj= { data: 'Lula Mae' }; function myFun() { console.log(this); } obj.myMethod = myFun; obj.myMethod(); // Object {data: "Lula Mae", myMethod: function}
      
      







通常の関数のように:



 var obj = { myMethod : function () { console.log(this); } }; var myFun = obj.myMethod; myFun(); // Window
      
      







evalによる実行(evalを使用しないでください):



 function myFun() { console.log(this); } var obj = { myMethod : function () { eval("myFun()"); } }; obj.myMethod(); // Window
      
      







メソッドの呼び出しまたは適用:



 function myFunc() { console.log(this); } var obj = { someData: "a string" }; myFunc.call(obj); // Object {someData: "a string"}
      
      







コンストラクター内:



 var Person = function(name){ this.name = name; console.log(this); } var person = new Person('Lula Mae'); // Person {name: "Lula Mae"}
      
      







ところで、コンストラクター関数は通常大文字で表記されます。



さらに最近では、関数をコンテキストにバインドするbindメソッドが登場しました。 より正確には、関数をコンテキストにバインドするだけでなく、callおよびapplyとは異なり、指定されたコンテキストで新しい関数を作成します。



 var myFunc = function() { console.log(this); }.bind(999); myFunc(); // Number {[[PrimitiveValue]]: 999}
      
      







短絡



JavaScriptは、ネストされた関数が外部関数の変数にアクセスできるように設計されています。 これが閉鎖です。



ジャックの例に戻りましょう。



 var callback = (function(i){ return function(a){ i++; return a + i; }; })(0); var str = 'Jack Jack Jack'.replace(/Jack/g, callback); console.log(str); // Jack1 Jack2 Jack3
      
      







引数aをとる関数が外部関数の変数にアクセスすることがありました。 そして、内部関数を呼び出すたびに、カウンター変数iを1増やします。



より簡単な例:



 function add(a) { var f = function(b) { return a+b; }; return f; } console.log(add(5)(7)); // 12
      
      







何が起こったのか見てみましょう。



関数が呼び出されると、そのコンテキストが作成されます。 関数の各変数がその名前を持つプロパティに対応するオブジェクトであると考えると便利です。 また、ネストされた関数を呼び出すと、外部関数のコンテキストへのリンクが取得され、変数にアクセスすると、関数のコンテキストで検索が実行され、その後、外部関数のコンテキストで検索が実行されます。



コールアド(5)



  1. [[scope]] = {a:5}によって生成
  2. 関数f = function(b){a + bを返す; }
  3. f関数は[[scope]]への参照を取得します
  4. 関数fへの参照が[[scope]]に追加されます
  5. 関数fへの参照を返します




コールアド(5)(7)



  1. [[scope2]] = {b:7}によって生成
  2. プロパティは[[scope2]]オブジェクトで検索されます。 見つかりません。
  3. プロパティは[[scope]]オブジェクトで検索されます。 見つかった、値は5です。
  4. オブジェクト[[scope2]]のプロパティbを検索します。 見つかった、値は7です。
  5. 5と7まで追加します。
  6. 加算の結果-数値12が返されます。




パラメータを渡す



 function myFunc(a, b){ console.log('myFunc begins'); console.log('myFunc ' + a); console.log('myFunc ' + b); } function getArgument(arg){ console.log('getArgument ' + arg); return arg; } myFunc(getArgument(5), getArgument(7)); // getArgument 5 // getArgument 7 // myFunc begins // myFunc 5 // myFunc 7
      
      







それで何? 第一に、引数が関数に渡される前に計算されることは明らかです。これは、パラメーターを処理するためのいわゆる厳密な戦略です... この動作は標準で定義されており、実装に依存しません。



値は参照渡しまたは値渡しされますか? 文字列を除くプリミティブは、値によって渡されます。 文字列は参照によって渡され、値によって比較されます。 文字列は不変なので、これはメモリを節約し、副作用がありません。 オブジェクトは参照渡しされます。 関数への参照によって引数を渡す前に、リンクのコピーが作成され、呼び出された関数内にのみ存在することに注意してください。 つまり、言い換えると、オブジェクトは参照値によって渡されます。 例を見てみましょう:



 var a = { data: 'foo' }; var b = { data: 'bar' }; function change(arg){ arg.data = 'data'; } function swap(x, y){ var tmp = x; x = y; y = tmp; } change(a); swap(a, b); console.log(a); // Object {data: "data"} console.log(b); // Object {data: "bar"}
      
      







オブジェクトのプロパティを変更できることがわかりました-リンクのコピーは同じオブジェクトを参照しています。 また、リンクに新しい値を割り当てると、元のリンクではなく、関数に渡されたコピーにのみ影響します。



可変バブルと名前解決



そのようなコードを見てみましょう。



 var a = 1; function b(){ console.log(a); if (false){ var a = 2; } } b(); // undefined
      
      







なぜ1ではないのですか? 実際には、varを介して宣言された変数の場合、スコープは関数によって制限され、変数を浮動させるメカニズムもあります。 言語インタープリターは、常にスコープの先頭にあるすべての変数の宣言を保持します。 この場合、アナウンスのみが転送され、値の割り当ては転送されません。 上記のコードは次と同等です:



 var a = 1; function b(){ var a; console.log(a); if (false){ a = 2; } } b();
      
      







名前でオブジェクトを見つけるためのアルゴリズムは次のとおりです。



  1. 言語の事前定義変数を検索します。 見つかった場合は、それを使用します。
  2. 正式な関数パラメーターを検索します。 見つかった場合は、それを使用します。
  3. 宣言された関数の中から現在のスコープを検索します。 見つかった場合は、それを使用します。
  4. 宣言された変数の中から現在のスコープを検索します。 見つかった場合は、それを使用します。
  5. 上記のスコープに移動して、最初からやり直してください。




例外は、これらの例外が指定されていない一般的なルールの存在を確認します。 arguments変数は、まさにそのような例外です。 これは言語で事前定義された変数ですが、値を検索する場合は仮引数パラメーターが優先されます。



 function a(){ console.log(arguments); } function b(arguments){ console.log(arguments); } a(); // [] b(); // undefined
      
      







継承



Java、C#、C ++などの言語とは異なり、オブジェクトはJavaScriptに継承されません。 ただし、クラスは予約語であるため、そのような変数に名前を付けることはできません。



各オブジェクトには、プロトタイプと呼ばれる別のオブジェクトへのリンクが含まれています。 プロトタイプには、プロトタイプへのリンクなどが含まれています。 ある時点で、nullプロトタイプを持つオブジェクトが特定され、チェーンが終了します。



プロトタイプ継承モデルは、クラスベースの継承よりも強力であると考えられています。 この命題を支持して、次の議論があります。クラスの継承は、プロトタイプの上にかなり簡単に実装されますが、反対に-いいえ。



JavaScriptのオブジェクトは、単に関連性のあるプロパティディクショナリであることは既に述べました。 ここで、非表示のプロパティがまだあることがわかります。これは[[Prototype]]であり、コードでは使用できず、プロパティの「予約」ソースとして機能します。 この場合のプロパティ検索の様子を見てみましょう。



プロトタイプチェーンを作成しましょう



{a:1、b:2} ---> {b:3、c:4} ---> null



 console.log(oa); // 1
      
      







オブジェクトには独自のプロパティaがあるため、値を取得します。



 console.log(ob); // 2
      
      







オブジェクトには独自のプロパティbがあるため、値を取得します。 プロトタイプにもこのようなプロパティがありますが、テストしていません。 これは、プロパティの重複と呼ばれます。



 console.log(oc); // 4
      
      







オブジェクトにはプロパティcがありません。 しかし、それはプロトタイプにあり、プロトタイプのプロパティを使用します。



 console.log(od); // undefined
      
      







オブジェクトにdプロパティはありません。 試作品を探していますが、試作品もありません。 プロトタイプのプロトタイプで検索を続けますが、それはヌルです。 検索を停止し、プロパティが見つかりませんでした。未定義を返します。



メソッドでは、すべてがまったく同じように起こります。 それでも、メソッドはオブジェクトのプロパティでもあります。 1つの注意点-関数内のthisキーワードは、関数がプロトタイプで見つかった場合でも、プロトタイプではなくオブジェクトを指します。 原則として、これは論理的です。



プロトタイプをオブジェクトに割り当てる方法は? いくつかの方法があります。



まず、オブジェクト、配列、関数を作成するときにプロトタイプが自動的に割り当てられます。



 var o = {a: 1}; // o ---> Object.prototype ---> null var a = ["horse", "table"]; // a ---> Array.prototype ---> Object.prototype ---> null function getRandomNumber(){ return 4; } // getRandomNumber ---> Function.prototype ---> Object.prototype ---> null
      
      







次に、コンストラクターを介してオブジェクトを作成するときにプロトタイプを割り当てることができます。 この場合、オブジェクトのプロトタイプがコンストラクターのプロトタイプになります。



 function Animal(){ this.eat = function(){ console.log('eat called'); }; } function Cat(name){ this.name = name; }; Cat.prototype = new Animal(); var cat = new Cat('No name cat'); cat.eat(); // eat called console.log(cat.name); // No name cat console.log(cat.constructor); // Animal
      
      







[[Prototype]]プロパティは、新しいcat()が実行されるとCat.prototypeに設定されます。 ただし、catオブジェクトのconstructorプロパティには値Animalが割り当てられました。 コンストラクターが正しいままになるようにコードを修正できます。 行Cat.prototype.constructor = Cat;を追加します。



 function Animal(){ this.eat = function(){ console.log('eat called'); }; } function Cat(name){ this.name = name; }; Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; var cat = new Cat('No name cat'); cat.eat(); // eat called console.log(cat.name); // No name cat console.log(cat.constructor); // Cat
      
      







第三に、Object.createメソッドを使用してオブジェクトを作成するときに、プロトタイプを割り当てることができます。 プロトタイプは、このメソッドの最初の引数に示されています。



 var a = {a: 1}; // a ---> Object.prototype ---> null var b = Object.create(a); // b ---> a ---> Object.prototype ---> null console.log(ba); // 1
      
      







プロトタイプを割り当てることはできません。 プロトタイプは、オブジェクトではなく、コンストラクターのプロパティです。



 var o = { a: 1 }; o.prototype = { b: 2 }; console.log(ob); // undefined
      
      







ただし、Objectなどの組み込み型のプロトタイプは変更できます。 これは悪い習慣です。 組み込みプロトタイプを変更する場合に受け入れられる唯一のケースは、言語の新しいバージョンの機能のエミュレーションのみです。



厳格モード



このモードはディレクティブによって有効になります



 'use strict';
      
      







このディレクティブは、コードがECMAScript 5標準に従って実行されることを意味します。 おそらくより論理的で正確ですが、以前と同じではありません。 このディレクティブは、スクリプト全体またはネストされた関数を含む単一の関数に適用できます。 入れ子とは、関数内で宣言された関数を指します。 関数が他の場所で宣言され、「strict」関数内でのみ実行される場合、ディレクティブは機能しません。 これは例にはっきりと見られます。



 function a(){ console.log(arguments.callee); } (function() { "use strict"; function b(){ console.log(arguments.callee); } a(); // function a(){...} b(); // TypeError })();
      
      







そして、この例がブラウザコンソールで機能するように、自己呼び出し機能がここにあります。 コンソールで「厳密に使用」は機能外では機能しません。



何が変わるのでしょうか? まず、既に述べたように、arguments.calleeプロパティは使用できなくなります。



第二に、これは、nullまたは未定義の場合はグローバルオブジェクトに置き換えられません。また、プリミティブの場合はコンストラクターインスタンスにラップされます。



 (function() { "use strict"; var a = function(){ console.log(this); }.bind(null) a(); // null })(); (function() { var a = function(){ console.log(this); }.bind(null) a(); // Window })();
      
      







第三に、明示的に宣言せずにグローバル変数を作成することはできません。



 (function() { "use strict"; a = 0; // ReferenceError: a is not defined })();
      
      







4番目に、with(obj){}コンストラクトはサポートされなくなりました



第5に、同じキーを使用してオブジェクトを作成することはできません。



 (function() { "use strict"; var o = { p: 1, p: 2 }; // SyntaxError: Duplicate data property in object literal not allowed in strict mode })();
      
      







これだけではありませんが、すべてをリストするわけではありません。



プライベートおよびパブリック



この言語にはプライベートキーワードとパブリックキーワードはありませんが、プライベートデータとパブリックデータを分離できます。 今日のいくつかの方法、たとえばモジュールパターンがあります。



 blackBox = (function(){ var items = ['table', 'horse', 'pen', 48]; return { pop: function(){ return items[~~(Math.random() * items.length)]; } }; })(); console.log(blackBox.pop()); // 48 console.log(blackBox.items); // undefined
      
      







または、これを行うことができます:



 function BlackBox(){ var items = ['table', 'horse', 'pen', 48]; this.pop = function(){ return items[~~(Math.random() * items.length)]; }; } var blackBox = new BlackBox(); console.log(blackBox.pop()); // "pen" console.log(blackBox.items); // undefined
      
      







デバッグ



デバッガーステートメントは、デバッガーを呼び出します(使用可能な場合)。 この場合、スクリプトの実行はこの命令のある行で停止します。



たとえば、ポップアップメッセージの送信元を特定する必要がある場合、コンソールで実行できます。



 window.alert = function(){ debugger; };
      
      







これで、メッセージの代わりに、デバッガーが起動し、アラート呼び出しの場所でスクリプトが停止します。



関数の呼び出しスタックを記録すると便利な場合があります。 次の方法で実行できます。



 function a(){ console.log(new Error().stack); } function b(){ a(); } function c(){ b(); } c();
      
      






All Articles