me_javascript スキルから JavaScript 関数と関数式を学びます
1. 関数宣言と関数式
ECMAScript では、関数を作成する最も一般的な 2 つの方法は、関数式と関数宣言です。ECMA 仕様では、関数宣言には識別子 (識別子) が必要であるという 1 つの点だけが明確にされているため、この 2 つの違いは少しわかりにくいです。 ) (これは、誰もがよく関数名と呼ぶものです)、この識別子は関数式では省略できます:
関数宣言: 関数 関数名 (パラメータ: オプション){関数本体}
関数式: 関数 関数名 (オプション) (パラメータ: オプション) { 関数本体 }
つまり、関数名が宣言されていない場合は式であることがわかりますが、関数名が宣言されている場合、それが関数宣言であるか関数式であるかをどのように判断するのでしょうか。 ECMAScript はコンテキストによって区別されます。関数 foo(){} が代入式の一部である場合、関数 foo(){} が関数本体内に含まれている場合、またはプログラムの先頭にある場合、それは関数式です。関数宣言。
function foo(){} // 声明,因为它是程序的一部分 var bar = function foo(){}; // 表达式,因为它是赋值表达式的一部分 new function bar(){}; // 表达式,因为它是new表达式 (function(){ function bar(){} // 声明,因为它是函数体的一部分 })();
式と宣言の間には非常に微妙な違いがあります。まず、関数の宣言は、コードの最後の行にある場合でも、式が解析および評価される前に解析および評価されます。同じスコープ内の式は前に解析/評価されます。次の例を参照してください。関数 fn はアラートの後に宣言されますが、アラートの実行時には fn がすでに定義されています。
alert(fn()); function fn() { return 'Hello world!'; }
// 千万别这样做! // 因为有的浏览器会返回first的这个function,而有的浏览器返回的却是第二个 if (true) { function foo() { return 'first'; } } else { function foo() { return 'second'; } } foo(); // 相反,这样情况,我们要用函数表达式 var foo; if (true) { foo = function() { return 'first'; }; } else { foo = function() { return 'second'; }; } foo();
関数宣言はプログラムまたは関数本体内でのみ使用できます。構文的には、ブロック ({ … }) 内、たとえば if、while、または for ステートメント内にこれらを使用することはできません。 Block には Statement ステートメントのみを含めることができ、関数宣言などのソース要素は含めることができないためです。一方、ルールを詳しく見てみると、ブロック内で式を使用できる唯一の方法は、それが式ステートメントの一部である場合であることがわかります。ただし、仕様では、式ステートメントをキーワード関数で始めることはできないと明確に述べられています。これが実際に意味するのは、関数式を Statement ステートメントまたはブロック内に使用できないということです (ブロックは Statement ステートメントで構成されているため)。
2. 名前付き関数式名前付き関数式の場合は、もちろん名前が必要です。前の例 var bar = function foo(){}; は、名前付き関数式としては有効ですが、覚えておくべきことが 1 つあります。仕様では、周囲のスコープ内では識別子を有効にできないと規定されているため、新しく定義された関数のスコープ内でのみ有効です:
var f = function foo(){ return typeof foo; // function --->foo是在内部作用域内有效 }; // foo在外部用于是不可见的 typeof foo; // "undefined" f(); // "function"
最初に述べたように、名前を付けるとデバッグ プロセスがより便利になります。デバッグするときに、コール スタック内の各項目にそれを説明するための独自の名前があれば、デバッグ プロセスがより効果的になるからです。 、感覚が違います。
ヒント:ここに小さな質問があります。ES3 では、名前付き関数式のスコープ オブジェクトも Object.prototype のプロパティを継承します。これは、関数式に名前を付けるだけで、Object.prototype のすべてのプロパティもスコープに取り込まれることを意味します。結果は驚くべきものになるかもしれません。
var constructor = function(){return null;} var f = function f(){ return construcor(); } f(); //{in ES3 环境}
この動作に対する合理的な解決策は、関数式と同じ名前のローカル変数を作成し、それに null の値を割り当てることです。関数式宣言を誤ってホイストしない環境でも、var を使用して変数を再宣言すると、変数 g がバインドされたままになります。変数 g を null に設定すると、重複した関数をガベージ コレクションできるようになります。
3、调试器(调用栈)中的命名函数表达式
刚才说了,命名函数表达式的真正用处是调试,那到底怎么用呢?如果一个函数有名字,那调试器在调试的时候会将它的名字显示在调用的栈上。有些调试器(Firebug)有时候还会为你们函数取名并显示,让他们和那些应用该函数的便利具有相同的角色,可是通常情况下,这些调试器只安装简单的规则来取名,所以说没有太大价值,我们来看一个例子:不用命名函数表达式
function foo(){ return bar(); } function bar(){ return baz(); } function baz(){ debugger; } foo(); // 这里我们使用了3个带名字的函数声明 // 所以当调试器走到debugger语句的时候,Firebug的调用栈上看起来非常清晰明了 // 因为很明白地显示了名称 baz bar foo expr_test.html()
通过查看调用栈的信息,我们可以很明了地知道foo调用了bar, bar又调用了baz(而foo本身有在expr_test.html文档的全局作用域内被调用),不过,还有一个比较爽地方,就是刚才说的Firebug为匿名表达式取名的功能:
function foo(){ return bar(); } var bar = function(){ return baz(); } function baz(){ debugger; } foo(); // Call stack baz bar() //看到了么? foo expr_test.html()
然后,当函数表达式稍微复杂一些的时候,调试器就不那么聪明了,我们只能在调用栈中看到问号:
function foo(){ return bar(); } var bar = (function(){ if (window.addEventListener) { return function(){ return baz(); }; } else if (window.attachEvent) { return function() { return baz(); }; } })(); function baz(){ debugger; } foo(); // Call stack baz (?)() // 这里可是问号哦,显示为匿名函数(anonymous function) foo expr_test.html()
另外,当把函数赋值给多个变量的时候,也会出现令人郁闷的问题:
function foo(){ return baz(); } var bar = function(){ debugger; }; var baz = bar; bar = function() { alert('spoofed'); }; foo(); // Call stack: bar() foo expr_test.html()
这时候,调用栈显示的是foo调用了bar,但实际上并非如此,之所以有这种问题,是因为baz和另外一个包含alert(‘spoofed')的函数做了引用交换所导致的。
归根结底,只有给函数表达式取个名字,才是最委托的办法,也就是使用命名函数表达式。我们来使用带名字的表达式来重写上面的例子(注意立即调用的表达式块里返回的2个函数的名字都是bar):
function foo(){ return bar(); } var bar = (function(){ if (window.addEventListener) { return function bar(){ return baz(); }; } else if (window.attachEvent) { return function bar() { return baz(); }; } })(); function baz(){ debugger; } foo(); // 又再次看到了清晰的调用栈信息了耶! baz bar foo expr_test.html()
好的,整个文章结束,大家对javascript的认识又近了一步,希望大家越来越喜欢小编为大家整理的文章,继续关注跟我学习javascript的一系列文章。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Go 言語は、クロージャとリフレクションという 2 つの動的関数作成テクノロジを提供します。クロージャを使用すると、クロージャ スコープ内の変数にアクセスでき、リフレクションでは FuncOf 関数を使用して新しい関数を作成できます。これらのテクノロジーは、HTTP ルーターのカスタマイズ、高度にカスタマイズ可能なシステムの実装、プラグイン可能なコンポーネントの構築に役立ちます。

C++ 関数の名前付けでは、読みやすさを向上させ、エラーを減らし、リファクタリングを容易にするために、パラメーターの順序を考慮することが重要です。一般的なパラメータの順序規則には、アクション-オブジェクト、オブジェクト-アクション、意味論的な意味、および標準ライブラリへの準拠が含まれます。最適な順序は、関数の目的、パラメーターの種類、潜在的な混乱、および言語規約によって異なります。

効率的で保守しやすい Java 関数を作成するための鍵は、シンプルに保つことです。意味のある名前を付けてください。特殊な状況に対処します。適切な可視性を使用してください。

1. SUM 関数は、列またはセルのグループ内の数値を合計するために使用されます (例: =SUM(A1:J10))。 2. AVERAGE 関数は、列またはセルのグループ内の数値の平均を計算するために使用されます (例: =AVERAGE(A1:A10))。 3. COUNT 関数。列またはセルのグループ内の数値またはテキストの数をカウントするために使用されます。例: =COUNT(A1:A10)。 4. IF 関数。指定された条件に基づいて論理的な判断を行い、結果を返すために使用されます。対応する結果。

C++ 関数のデフォルト パラメーターの利点には、呼び出しの簡素化、可読性の向上、エラーの回避などがあります。欠点は、柔軟性が限られていることと、名前の制限があることです。可変引数パラメーターの利点には、無制限の柔軟性と動的バインディングが含まれます。欠点としては、複雑さの増大、暗黙的な型変換、デバッグの難しさなどが挙げられます。

C++ で参照型を返す関数の利点は次のとおりです。 パフォーマンスの向上: 参照による受け渡しによりオブジェクトのコピーが回避され、メモリと時間が節約されます。直接変更: 呼び出し元は、返された参照オブジェクトを再割り当てせずに直接変更できます。コードの簡素化: 参照渡しによりコードが簡素化され、追加の代入操作は必要ありません。

カスタム PHP 関数と定義済み関数の違いは次のとおりです。 スコープ: カスタム関数はその定義のスコープに限定されますが、事前定義関数はスクリプト全体からアクセスできます。定義方法: カスタム関数は function キーワードを使用して定義されますが、事前定義関数は PHP カーネルによって定義されます。パラメータの受け渡し: カスタム関数はパラメータを受け取りますが、事前定義された関数はパラメータを必要としない場合があります。拡張性: カスタム関数は必要に応じて作成できますが、事前定義された関数は組み込みで変更できません。

C++ の例外処理は、特定のエラー メッセージ、コンテキスト情報を提供し、エラーの種類に基づいてカスタム アクションを実行するカスタム例外クラスを通じて強化できます。 std::Exception から継承した例外クラスを定義して、特定のエラー情報を提供します。カスタム例外をスローするには、throw キーワードを使用します。 try-catch ブロックでdynamic_castを使用して、キャッチされた例外をカスタム例外タイプに変換します。実際の場合、open_file 関数は FileNotFoundException 例外をスローします。例外をキャッチして処理すると、より具体的なエラー メッセージが表示されます。
