2

私はすでにこのコードを機能させる方法を知っていますが、私の質問は、なぜそれがこのように機能するのか、そして私が正しいことをしているのかということです。

私の問題を紹介するために私が作ることができる最も簡単な例はこれです:

ボタンを押すだけで入力フィールドの値を10ずつ増やす関数があるとしましょう。

var scopeTest = {

    parseValue : function( element, value ) {
        value = parseInt( element.val(), 10 );
        //Why does this not return the value?
        return value;
    },


    incrementValue : function( element, button, value ) {
        button.on('mousedown', function (e) {
            //Execute the parseValue function and get the value
            scopeTest.parseValue( element, value ); 
            //Use the parsed value      
            element.val( value + 10 );    
            e.preventDefault(); 
        });               
    },


    init : function () { 
        var element = $('#test-input'),
            button = $('#test-button'),
            value = ''; 

        this.incrementValue( element, button, value );
    }

};

scopeTest.init();

メソッド内で実行すると、メソッドがvarをparseValue適切に返さないため、上記のコードは機能しません。valueincrementValue

どうやらそれを解決するには、次のようにscopeTest.parseValue( element, value );パラメータをvalue変数に設定する必要があります。

value = scopeTest.parseValue( element, value );

コードが機能するより。

しかし、私の質問はなぜですか?なぜこの余分な変数代入ステップが必要なのですか、なぜreturnステートメントでは不十分なのですか?また、私は自分の関数/メソッドですべてを正しく行っていますか、それともこれはJavaScriptが機能する方法ですか?

ここでの実例=> http://jsfiddle.net/Husar/zfh9Q/11/

4

5 に答える 5

2

parseValueへのパラメーターは単なる参照であるためです。はい、参照があるため、オブジェクトを変更できますが、参照に割り当てると、別のオブジェクトを指すようになります。

元のバージョンは変更されていません。はい、戻り値は「十分」でしたが、次のコード行で終了する有効期間を持つ変数に新しいオブジェクトを保存しました。

JavaScript は参照によってオブジェクトを渡すとよく言われますが、これを文字通りに捉えすぎると混乱する可能性があります。JavaScript のすべてのオブジェクト ハンドルは参照です。この参照自体は参照によって渡されません。つまり、二重間接ポインターは取得されません。したがって、仮パラメーターを使用してオブジェクト自体を変更することはできますが、呼び出しサイトの参照自体を変更することはできません。

于 2012-04-15T19:22:48.727 に答える
1

他の人が言っているように、それはpass-by-refpass-by-valです。

与えられた: function foo (){return 3+10;} foo();
何が起こりますか?操作は実行されますが、その値はどこにも設定されていません。

一方: result = foo();
操作は実行されますが、将来の使用のためにその値を保存しました。


それは少し範囲の問題です

  • var param = 0;  
    function foo( param ) { 
       param = 1; 
    } 
    foo(param);
    console.log(param);                  // still retains value of 0
    

なんで?

グローバルなものがありますがparam、関数内では引数の名前が呼び出されるparamため、関数はグローバルを使用しません。代わりにparam、ローカルインスタンス(this.param)のみを適用します。これを行った場合、これは完全に異なります。

  • var param = 0;  
    function foo() {                     // notice no variable 
       param = 1;                        // references global
    } 
    foo(param);
    console.log(param);                  // new value of 1
    

ここでは、と呼ばれるローカル変数がないparamため、グローバルを使用します。

于 2012-04-15T19:39:55.720 に答える
1

これは主にスコープの問題です。送信者変数と呼び出された関数変数の名前が同じであるため、pass-by-*の問題について説明するのは奇妙です。とにかくやってみます。

変数には、それが表示されるスコープがあります。何かを格納する場所として見ることができます。このスコープは、関数の場所によって定義されます。ソースコード内(グローバルスコープ内または関数スコープ内)のどこにあるかを意味します。これは、後で関数を呼び出す方法ではなく、ソースコードを記述するときに定義されます。

スコープはネストできます。あなたの例では、4つのスコープがあります。グローバルスコープと各関数にはスコープがあります。関数のスコープはすべて、親スコープとしてグローバルスコープを持っています。親スコープとは、名前/変数にアクセスしようとすると、関数スコープで最初に検索され、見つからない場合は、名前/変数が見つかるか、グローバルスコープに到達するまで、親スコープに検索が進むことを意味します(その場合、見つからないというエラーが発生します)。

同じ名前を複数回定義することができます。それがあなたの混乱の原因だと思います。目の「値」という名前は常に同じですが、スクリプトには3回存在します。各関数はそれを定義しています:パラメーターとしてparseValueとincrementValue、ローカル変数としてinit。この効果はシャドウイングと呼ばれます。これは、「value」という名前のすべての変数が常に存在することを意味しますが、名前を検索すると、一方が以前に見つかったため、もう一方が非表示/シャドウになります。

この場合、ローカル変数とパラメーターのスコープが同じであるため、「値」は3つの関数すべてで同様に扱われます。これは、メソッドの1つを入力するとすぐに、関数スコープを入力することを意味します。スコープを入力すると、「value」という名前がスコープチェーンに追加され、関数の実行中に最初に検出されます。そして、その逆が真実です。関数スコープが残されている場合、「値」はスコープチェーンから削除され、非表示になって破棄されます。

ここでは、パラメータ「value」を受け取る関数を「value」という名前の関数で呼び出しても、意味が異なるため、非常に混乱します。異なるため、ある「値」から別の「値」に値を渡す必要があります。何が起こるかというと、外側の「値」の値が内側の「値」にコピーされます。それが値渡しの意味です。コピーされる値は、オブジェクトへの参照である可能性があります。これは、ほとんどの人が参照渡しであると信じているものです。紛らわしいと思われる場合は申し訳ありませんが、ここでは値の命名が多すぎます。

値は外部関数から呼び出された関数にコピーされ、呼び出された関数の内部にのみ存在します。関数が終了すると、行ったすべての変更は破棄されます。唯一の可能性はあなたの「副作用」を返すことです。これは、関数が破棄される直前に、作業が変数にコピーバックされることを意味します

他の選択肢としては、実際にパラメーターを残して、スコープチェーン(グローバルスコープなど)を操作することです。しかし、そうしないことを強くお勧めします。使いやすいように見えますが、微妙なエラーが多く発生し、生活が非常に困難になります。最善の方法は、変数のスコープが最も狭いことを確認し(変数が使用される場所)、関数パラメーターごとの値と戻り値を渡すことです。

于 2012-04-16T07:53:33.133 に答える
1

これはスコープの問題ではなく、参照渡しと値渡しの混同です。

JavaScript では、すべての数値が値渡しされます。つまり、次のようになります。

var value = 10;
scopeTest.parseValue( element, value );
// value still == 10

オブジェクトと配列は参照によって渡されます。つまり、次のことを意味します。

function foo( obj ){
    obj.val = 20;
}

var value = { val: 10 }
foo( value );
// value.val == 20;
于 2012-04-15T19:24:05.483 に答える
-1

あなたはそれを見るかもしれません。

http://snook.ca/archives/javascript/javascript_pass

于 2012-04-15T19:24:45.743 に答える