1

さて、私は本当に単純なものを見落としているというこっそりの疑いがありますが、次のコードに問題があります:

Array.prototype.sortArr = function (skey)
{
    var vals = new Array();
    for (key in this)
    {
        if (typeof(this[key][skey]) != 'undefined')
        {
            vals.push((this[key][skey]+'').toLowerCase());
        }
    }
    vals.sort();

    var newArr = new Array();
    for (i=0;i<vals.length;i++)
    {
        for (key in this)
        {
            if (typeof(this[key][skey]) != 'undefined')
            {
                if ((this[key][skey]+'').toLowerCase() == vals[i])
                {
                    newArr.push(this[key]);
                    break;
                }
            }
        }
    }
    return newArr;
}

簡単に言うと、この関数は、マルチレベルオブジェクトを並べ替える点と、並べ替える必要のあるキーを指定する点を除いて、並べ替え関数に似ています。
問題は、「this」値を実際に置き換えたり変更したりしないことです。つまり、この関数は実際には何もしません。例えば:

var arr = new Array(new Array(1,5),new Array(2,0));
arr.sortArr(1);

通話arrの前後から変更されることはありません。sortArr(1)ただし、関数が戻る直前に右に置くと、alert(newArr)実際に並べ替えられたことがわかります。だから、私の質問は; thisコールバック関数の値を置き換える、または少なくとも適切な/新しい配列を返すにはどうすればよいですか?前もって感謝します。

4

3 に答える 3

1

メソッドの最後で現在の配列を変更するには、次のようにその要素に割り当てる必要があります。関数が終了する前に、すべての要素を現在のオブジェクトの配列にコピーします。

this.length = newArr.length;
for (var i = 0; i < newArr.length; i++) {
    this[i] = newArr[i];
}

.splice()次のように使用することもできます。

newArr.unshift(this.length);     // how many items to remove for .splice()
newArr.unshift(0);               // index for .splice() operation
this.splice.apply(this, newArr); // add the newArr elements

for/in参考までに、配列要素に加えてオブジェクトのプロパティも繰り返すため、配列で構成を使用することは一般的に正しくありません。これにより、多くの場合、問題が発生します。配列内の項目を反復処理する場合は、上記のコードスニペットで行ったように、従来のforループを使用します。

于 2012-07-19T04:42:28.607 に答える
0

実装したら、新しい配列を返します。元の配列を新しい結果に置き換える場合は、明示的に行う必要があります。

var arr = new Array(new Array(1,5),new Array(2,0)); 
arr = arr.sortArr(1);

しかし、それはあなたがやりたいことではないように思えます。

于 2012-07-19T04:48:46.637 に答える
0
var newArray = [{},"Bob",32].sortArr();

関数の先頭に戻るのではなく、 return ステートメントを考えてください... ...左側から出ると考えてください。

したがって、関数を定義するときは、引数の代わりにパラメーターを配置します。渡されたオブジェクトをそのまま並べ替えたい場合は、オブジェクトのコピーを保存せずに、元のオブジェクトである AS-IS に対して操作を行う必要があります。

つまり、次のとおりです。

function addBob (obj) {
    obj.name = "Bob";
    return undefined;
    // any fn without a return mentioned returns undefined, anyway.
    // I just put this here for reference.
}

このバージョンの addBob は name : "Bob" を元のオブジェクトに追加します。

function addBob2 (obj) {
    bobject = obj;
    bobject.name = "Bob";
    return undefined;  // again, if you don't state a return, that's what you get
}

わかった。ここで問題が発生しました。見えますか?

関数の先頭にオブジェクトを配置し、オブジェクトのローカル コピーを保存しました (これは良いことですが、ここではそうではありません)。

次に、コピーを変更しました。

あなたは終わったと思います。しかし、あなたはそうではありません。何も変わっていません。なんで?

変更を元に戻さなかったからです。それには、次の 2 つの方法があります。

  1. function addBob3(obj) { var localObj = obj; localObj.name = "ボブ"; obj = localObj; }

    addBob3(externalObj);

この関数は、計算を行うためにローカル コピーを保存するように作成されていますが、計算が完了すると、元のオブジェクトまたはオブジェクトのプロパティを上書きします。つまり、次のようになります。

obj.name = localObj.name;

これにより、データが元のオブジェクトに戻されます (つまり、関数の先頭から)。一部の人々は、この悪い習慣を考えています。なぜなら、これらの場内変更関数が多数ある場合、10,000 行のプログラムに入ったときに、どのオブジェクトがどの関数によって変更されたかを判断するのが難しいからです。

今はあまり心配しないでください。

それを行うその他の方法:

function addBob4(obj) {
    var localObj = obj;
    localObj.name = "Bob";
    return localObj;
}


var externalObj = { property1 : "something" },

newObj = addBob4(externalObj);

これで、関数呼び出しのLEFTに出力される戻り値が得られました。newObj は、コピーに加えた新しい追加を除いて、externalObj とまったく同じオブジェクトになります。

そのため、戻り値を変数に取り込めば、関数は左側から終了できます。また、渡したオブジェクトをその場で直接変更すると、関数が終了した後、それらの編集が元のオブジェクトに適用されます。

「これ」を扱うのは少しトリッキーです。オブジェクトの場合は、「this.name = 'Bob';」を実行するだけです。これで完了です。

配列の場合、基本的に this[0] - this[this.length - 1] を空にしてから、this[0] - this[newArr.length - 1] を埋める 3 番目のループが必要です。 newArr の値を使用します。JavaScript では、"this" を展開して "this = X" ステートメントに変換することはできないからです。

于 2012-07-19T05:27:18.887 に答える