4

配列の戻り値と変異を正規化する JavaScript 配列ライブラリはありますか? JavaScript Array API は非常に一貫性がないと思います。

一部のメソッドは配列を変更します。

var A = [0,1,2];
A.splice(0,1); // reduces A and returns a new array containing the deleted elements

しないものもあります:

A.slice(0,1); // leaves A untouched and returns a new array

変更された配列への参照を返すものもあります。

A = A.reverse().reverse(); // reverses and then reverses back

undefined を返すものもあります:

B = A.forEach(function(){});

私が望むのは、常に配列を変更し、常に同じ配列を返すことです。これにより、ある種の一貫性を保ち、連鎖することもできます。例えば:

A.slice(0,1).reverse().forEach(function(){}).concat(['a','b']);

次のような簡単なスニペットをいくつか試しました。

var superArray = function() {
    this.length = 0;
}

superArray.prototype = {
    constructor: superArray,

    // custom mass-push method
    add: function(arr) {
        return this.push.apply(this, arr);
    }
}

// native mutations
'join pop push reverse shift sort splice unshift map forEach'.split(' ').forEach(function(name) {
    superArray.prototype[name] = (function(name) {
        return function() {
            Array.prototype[name].apply(this, arguments);
            // always return this for chaining
            return this;
        };
    }(name));
});

// try it
var a = new superArray();
a.push(3).push(4).reverse();

これは、ほとんどのミューテーション メソッドで問題なく機能しますが、問題があります。たとえば、元の配列を変更しない各メソッドのカスタム プロトタイプを作成する必要があります。

いつものように、これをやっている間、これは以前に行われたのではないかと考えていました。これを行う軽量の配列ライブラリは既にありますか? ライブラリが、古いブラウザ用の新しい JavaScript 1.6 メソッドの shim も追加するとよいでしょう。

4

3 に答える 3

2

本当に矛盾しているとは思いません。はい、JavaScript 配列は他の言語が個別の構造 (リスト、キュー、スタックなど) を持つすべてのことを行うため、少し混乱するかもしれませんが、それらの定義は言語間で非常に一貫しています。すでに説明したカテゴリに簡単にグループ化できます。

  • メソッドのリスト:
    • push/unshift要素を追加した後に長さを返す
    • pop/shift要求された要素を返す
    • 最初と最後の要素を取得するための追加のメソッドを定義できますが、ほとんど必要ありません
  • spliceリストの途中にある項目を削除/置換/挿入するための多目的ツールです。削除された要素の配列を返します。
  • sortreverseは、2 つの標準的なインプレース並べ替え方法です。

他のすべてのメソッドは、元の配列を変更しません。

  • sliceサブ配列を位置でfilter取得する、条件で取得するconcat、他のものと結合する 新しい配列を作成して返す
  • forEach配列を反復するだけで何も返さない
  • every/some条件についてアイテムをテストし、アイテムをindexOf検索lastIndexOfします(同等性による)-両方が結果を返します
  • reduce/reduceRight配列項目を単一の値に減らし、それを返します。特殊なケースは次のとおりです。
    • map新しい配列に縮小します-似てforEachいますが、結果を返します
    • joinそしてtoString文字列に減らします

これらの方法は、ほとんどのニーズに十分対応できます。私たちはそれらを使ってあらゆることを行うことができます.同様のライブラリを知りませんが、内部的または結果的に異なるメソッドをそれらに追加します. ほとんどのデータ処理ライブラリ ( Underscoreなど) は、それらをクロス ブラウザー セーフ ( es5-shim ) にするだけで、追加のユーティリティ メソッドを提供します。

私が望むのは、常に配列を変更し、常に同じ配列を返すことです。これにより、ある種の一貫性を保ち、連鎖することもできます。

JavaScript の一貫性は、要素または長さが変更されたときに常に新しい配列を返すことだと思います。これは、オブジェクトが参照値であり、それらを変更すると、同じ配列を参照する他のスコープで副作用が頻繁に発生するためだと思います。

sliceconcatsortreversefilterおよび を一緒に使用mapして、1 つのステップだけで新しい配列を作成できます。配列のみを「変更」したい場合は、配列変数に再割り当てするだけです。

A = A.slice(0,1).reverse().concat(['a','b']);

Mutation メソッドには、私にとって 1 つの利点しかありません。メモリ効率が向上する可能性があるため、高速です (もちろん、実装とそのガベージ コレクションによって異なります)。それでは、それらのためのいくつかのメソッドを実装しましょう。配列のサブクラス化は可能でも有用でもないため、ネイティブ プロトタイプで定義します

var ap = Array.prototype;
// the simple ones:
ap.each = function(){ ap.forEach.apply(this, arguments); return this; };
ap.prepend = function() { ap.unshift.apply(this, arguments); return this; };
ap.append = function() { ap.push.apply(this, arguments; return this; };
ap.reversed = function() { return ap.reverse.call(ap.slice.call(this)); };
ap.sorted = function() { return ap.sort.apply(ap.slice.call(this), arguments); };
// more complex:
ap.shorten = function(start, end) { // in-place slice
    if (Object(this) !== this) throw new TypeError();
    var len = this.length >>> 0;
    start = start >>> 0; // actually should do isFinite, then floor towards 0
    end = typeof end === 'undefined' ? len : end >>> 0; // again
    start = start < 0 ? Math.max(len + start, 0) : Math.min(start, len);
    end = end < 0 ? Math.max(len + end, 0) : Math.min(end, len);
    ap.splice.call(this, end, len);
    ap.splice.call(this, 0, start);
    return this;
};
ap.restrict = function(fun) { // in-place filter
    // while applying fun the array stays unmodified
    var res = ap.filter.apply(this, arguments);
    res.unshift(0, this.length >>> 0);
    ap.splice.apply(this, res);
    return this;
};
ap.transform = function(fun) { // in-place map
    if (Object(this) !== this || typeof fun !== 'function') throw new TypeError();
    var len = this.length >>> 0,
        thisArg = arguments[1];
    for (var i=0; i<len; i++)
        if (i in this)
            this[i] = fun.call(thisArg, this[i], i, this)
    return this;
};
// possibly more

今、あなたはできる

A.shorten(0, 1).reverse().append('a', 'b');
于 2012-11-12T18:54:40.063 に答える
1

IMHO 最高のライブラリの 1 つは underscorejs http://underscorejs.org/です。

于 2012-11-09T13:30:11.223 に答える
0

おそらく、これだけのためにライブラリを使用するべきではありません (プロジェクトに追加するのはあまり役に立たない依存関係です)。

「標準的な」方法は、slice変更操作を実行したいときに呼び出すことです。JS エンジンは一時変数に非常に適しているため、これを行うことに問題はありません (これは JavaScript の重要なポイントの 1 つであるため)。

元。:

function reverseStringify( array ) {
    return array.slice( )
        .reverse( )
        .join( ' ' ); }

console.log( [ 'hello', 'world' ] );
于 2012-11-13T05:33:59.070 に答える