27

重複の可能性:
JavaScript: var functionName = function() {} vs function functionName() {}
Javascript での関数式と宣言の違いは何ですか?

関数宣言と式の違いは認識していますが、関数名を含むこのコードに出くわし、実行するとどうなるかを理解したいと考えています。

var abc = function def() {
    console.log("Wait! What??");
}

これが JavaScript の方法ではないことはわかっていますが、いくつか知りたいことがあります。

  1. はどうなりabcますか?なぜそれが機能するのですか?abcを呼び出すことはできますが、呼び出すことはできませんdef。なぜですか?
  2. 関数宣言ですか、それとも式ですか。
  3. defundefined- なぜですか?想定されている場合、メモリリークはありますか?
  4. なぜ is abc.prototypefunction なのdefですか?

ありがとう

4

5 に答える 5

11

abcはどうなるの?

関数オブジェクトが含まれています。何もしていない場合は、ガベージコレクションされます。

なぜそれが機能するのですか?

なぜだめですか?「効く」って何?

abc は呼び出せますが、def は呼び出せません。なぜですか?

これは外部からのみ当てはまり、IE では当てはまりません。下記参照。

関数宣言ですか、それとも式ですか。

関数式です。これは代入式の一部であるため、簡単に確認できます。宣言は常に (関数またはグローバル コードの) トップ レベルにある必要があります。

def は定義されていません - なぜですか?

外からだけ。関数式は変数を作成しません。「def」は関数の名前であり、関数内では関数への参照でもあります。これにより、たとえば、外部変数を使用せずに再帰が可能になります。

var abc = function def() {
    def === abc; // true
    def.name; // "def"
}
abc();
def; // undefined

想定されている場合、メモリリークはありますか?

はい、Internet Explorer で。そのコードから 2 つの異なる関数を作成します。詳細については、http://kangax.github.com/nfe/#jscript-bugsを参照してください。

abc.prototype が関数定義であるのはなぜですか?

そうではない。それは単なるオブジェクトです。「def」という名前の関数に属しているため、コンソールにその名前で表示される場合があります。

于 2013-01-17T08:27:05.403 に答える
5

名前付きの関数式です。これの可能な用途は次のとおりです。

var abc = function def() {
    def.test = 'Wait!'; //< sort of a static property
    console.log(def.test+" What??");
}

しかし、注意してください

于 2013-01-17T08:16:22.660 に答える
2

関数式2です

関数式にも名前を付けることができます関数式の名前は、関数本体のスコープ内にのみ含まれます1。(ECMAScript 第 5 版では が廃止さarguments.calleeれるため、これが再帰的な「無名」関数を記述する唯一の簡単な方法です。)

これ関数式であるため、名前によって外部スコープに新しいバインディングが導入されることはありません。

また、すべての関数は JavaScript のオブジェクトです。ではf(..)、で「呼び出される」fに評価されます。関数に評価されなかった場合、エラーがスローされます。これが、単なる関数であるコールバックが変数によって名前を付けられ、パラメーターとして渡される理由です。(..)f

また、プロトタイプに関する仮定/主張を確認してください。

var abc = function def() {}
abc.prototype === abc // -> false
abc.name              // -> "def"

1 Bergi の回答を参照してください。

2どちらがどれであるかを簡単に見分ける方法は?

ほとんどのエンジンは [誤って] Function Declaration をStatementとして解析しますが、文法規則はそれがSourceElementの場合にのみfunction ..Function Declaration として解析することを許可します。SourceElement 生成は、プログラムの最上位の「ブロック」または関数の最上位の「ブロック」でのみ発生します。

いずれにせよ、Expression必要function ..場所に が現れると、関数式として解析されますすべて関数式として解析される例:

// Can only assign values: Statements do not have values!
var f = function () {}        
var g = function gName () {}  // see Bergi's answer

// Can only pass values: Statements do not have values!
doIt(function () {})          // callback / "anonymous function"

// IIFE: Immediately-Invoked Function Expression
;(function () {})()           // standard IIFE
;(function () {} ())          // alternative standard IIFE
;+function () {} ()           // curious way to write an IIFE
// basically you can use any unary operator to turn it into an expression not only
//  + but also - ! ~ and so on which will modify the return value accordingly

ポイントは、上記のすべてのケースで、が式を必要とfunction ..する文法の場所に出現するため、関数式として解析されることです。(上記の行の先頭にあるセミコロンは、ASI での「あいまいさ」を回避します。これは、私が好むセミコロンのないスタイルで記述するときに必要です。)

でも。;function () {} ()両方とも;function f () {} ()無効な構文です-なぜですか? ;-)

于 2013-01-17T08:16:11.843 に答える
2

名前付き関数式です。

関数宣言に反して、関数式の識別子は必須ではありません。

関数defはすぐには呼び出されません。関数全体が渡されabc、明示的に呼び出す必要がありますabc()

ES5仕様の§13は、名前付き関数式がどのように構築されるかを述べています。名前付き関数式の作成方法に関する 3 番目の生成規則を読んでください。

注 FunctionExpression の Identifier は、FunctionExpression の FunctionBody 内から参照して、関数が自身を再帰的に呼び出すことができます。ただし、FunctionDeclaration とは異なり、FunctionExpression の Identifier は参照できず、FunctionExpression を囲むスコープには影響しません。

最近のすべてのブラウザーはこれを正しく処理するため、メモリ リークやその他の奇妙なことを心配する必要はありません (誤った処理は古い IE <=8 でのみ発生します)。

于 2013-01-17T08:21:49.943 に答える
1

あなたの例は(名前付き)関数式です。

2 つの違いは、ブラウザがそれらをロードする方法にあります。

関数宣言は、コードが実行される前に読み込まれます。関数式は、インタープリターがそのコード行に到達したとき
に のみ読み込まれます。

これの意味は:

abc();
var abc = function() {
    console.log("Wait! What??");
}

動作しませんが:

def();
function def() {
    console.log("Wait! What??");
}

意思。

あなたの例では、にアクセスできますdefが、関数自体の内部のみです。

var abc = function def() {
    console.log(def);
}
abc();

// Logs:
//function def() {
//    console.log(def);
//}
于 2013-01-17T08:16:06.587 に答える