0

CoffeeScript によって生成されたこの JavaScript コードを理解しようとしています。

私は次のように定義された関数を見ることに慣れています:

  • function Animal(name) {...}
  • var Animal = function(name){...};

しかし、CoffeeScript は以下を生成します。

var Animal = (function() {
  function Animal(name) {
    this.name = name;
  }

  return Animal;

})();

質問:

  • 無名関数内に「名前付き」関数を作成するとどうなりますか?
  • Animal 関数をこのように定義することと、箇条書きの 2 つの方法のうちの 1 つを定義することの利点は何ですか?

おまけ質問 これらは同等ですか?

//Methodology #1
function Animal(name) {...}
//Methodology #2
var Animal = function Animal(name) {...};
4

4 に答える 4

1
  1. 無名関数内に「名前付き」関数を作成するとどうなりますか?

    アップデート

    これは IE8 にのみ当てはまります。これは、JScript のバグのためです。最近の (そして健全な) ブラウザーでは、名前付き関数式を使用する場合、アニマルはコンテキスト名前空間に登録されません。

    関数宣言が関数名をコンテキスト (グローバル名前空間である可能性があります) に登録するのを防ぎます。つまり、これを行う場合:

    var Tiger = function Animal() {};
    

    Tigerとの両方Animalがグローバル名前空間に登録されますが、これは次のとおりです。

    var Tiger = function() { function Animal() {}; return Animal; };
    

    Animalグローバル名前空間にのみ登録します。

  2. Animal 関数をこのように定義することと、箇条書きの 2 つの方法のうちの 1 つを定義することの利点は何ですか?

    アップデート

    繰り返しますが、これは IE8 よりも新しいブラウザーで動作している場合には有効ではありません。このような場合、コンテキストを気にせずに名前付き関数式を使用できます。

    利点は、コンテキスト (これもグローバルである可能性があります) の名前空間をクリーンに保ちながら、オブジェクトの名前付きコンストラクターを引き続き使用できることです。つまり、次のことを意味します。

    var Tiger = function() {};
    var t = new Tiger();
    t.constructor // is an anonymous function() {}
    

    よりも宣言的ではない

    var Tiger = function() { function Animal() {}; return Animal };
    var t = new Tiger();
    t.constructor // is a function Animal()
    Animal //=> is not defined
    

    そして、これはグローバル名前空間またはコンテキスト名前空間を潜在的に不要な登録で汚染しますAnimal

    var Tiger = function Animal() {};
    var t = new Tiger();
    t.constructor // is a function Animal()
    Animal //=> returns function Animal();
    
  3. これらは同等ですか?

    アップデート

    これはすべてのブラウザに当てはまります。

    いいえ。最初の例では の名前で関数をAnimal宣言しますが、2 番目の例では の名前で宣言された関数を の名前のAnimal変数に代入します。これは名前付き関数式Animalとして知られています。1 つ目では、ルックアップは関数名によって機能し、2 つ目では、ルックアップは変数名によって機能します。これは、関数宣言が関数を上書きできないためです。関数宣言はスクリプトの読み込み時にコンテキストに読み込まれますが、式の割り当てはスクリプトの実行時に実行されます。

    function a() { 
      var b = function() { return 3; }; 
      return b(); 
      function b() { return 9; } 
    }
    
    a() //=> returns 3;
    
于 2013-04-22T16:19:24.560 に答える
0

「無名関数内に「名前付き」関数を作成するとどうなりますか?」

ネストされている関数内の変数スコープに対してローカルな新しい関数を作成するだけです。

「アニマル関数をこのように定義することと、箇条書きの 2 つの方法のうちの 1 つを定義することの利点は何ですか?」

示されているコードを考えると、特別な利点はありませんが、その外側の関数内に他の変数がある場合、その内側の関数はそれらを参照して、それらへの制御されたアクセスを提供できます(それ以外の場合、変数はその外側の関数の外側からアクセスできないため)

これが可能になるのは、JavaScript 関数がいわゆるクロージャーを形成するためです。つまり、変数スコープから削除された場合でも、元の変数スコープが保持されます。

おまけ質問これらは同等ですか?」

元のコードに?はい、基本的に同等です。

ほとんどの場合、お互いに。主な違いは、関数宣言(方法 1)が「ホイスト」されていることです。つまり、関数宣言はスコープの最上位で使用できるため、定義する前に実際に使用できます。

関数式は、式が評価された後にのみ使用できます。


すべての関数には名前があるため、すべてデバッグ コンソールに表示されることに注意してください。また、すべての関数は同じ変数スコープになります

于 2013-04-22T16:08:11.000 に答える
0

OOP (オブジェクト指向プログラミング)をご存知ですか?

classここに表示されているのは、JavaScript にキーワードがなくても、JavaScript でオブジェクトを定義しようとしているからです。

Java (JavaScript とはほとんど関係がない) について少し知っている場合は、次のように理解できるはずです。

public class Animal { // creating a class
    private String name; // declaring its attributes

    public Animal(String name) { // declaring constructor
        this.name = name; // assigning value to the attribute
    }
}

あなたが与えた JavaScript コードは基本的に同じことを行います。たとえば、属性(変数が割り当てられている) とメソッド(関数が割り当てられている)の両方を持つクラス (ある種の拡張型) を作成します。

だからこのコード

function Animal(name) {
    this.name = name;
}

クラスを作成しAnimalます。

問題は、JavaScript には実際にはclassの概念はなく、 objectsの概念しかないということです。ここで変数を作成し、次の関数の結果を代入します。

var Animal = (function() {
    // some code here
})
(); // note the parenthesis here that means the function is called

次に、コンストラクターが定義され、この関数を含むオブジェクトが返されます。

したがって、実行の最後にvar Animalコンストラクターが含まれているため、任意のオブジェクトを次のように初期化できます̀var myAnimal = new Animal('Panther');

それが役立つことを願っています。

于 2013-04-22T16:25:46.830 に答える