“Argümanlar” nesnesini JavaScript'teki bir diziye nasıl dönüştürebilirim?


433

argumentsJavaScript nesne garip bir siğil-sadece çoğu durumda bir dizi gibi davranan, ama değil aslında bir dizi nesne. Öyle yana tamamen başka gerçekten bir şey , ondan kullanışlı işlevler yok Array.prototypegibi forEach, sort, filterve map.

Basit bir döngü ile bir argüman nesnesinden yeni bir dizi oluşturmak çok kolaydır. Örneğin, bu işlev bağımsız değişkenlerini sıralar:

function sortArgs() {
    var args = [];
    for (var i = 0; i < arguments.length; i++)
        args[i] = arguments[i];
    return args.sort();
}

Ancak, bu son derece kullanışlı JavaScript dizisi işlevlerine erişmek için yapmanız gereken oldukça zavallı bir şeydir. Standart kitaplığı kullanarak bunu yapmanın yerleşik bir yolu var mı?


Yanıtlar:


725

Dinlenme parametrelerini kullanan ES6

ES6 kullanabiliyorsanız şunları kullanabilirsiniz:

Dinlenme Parametreleri

function sortArgs(...args) {
  return args.sort(function (a, b) { return a - b; });
}

document.body.innerHTML = sortArgs(12, 4, 6, 8).toString();

Eğer okuduğunuz gibi bağlantı

Rest parametresi sözdizimi, bir dizi olarak belirsiz sayıda bağımsız değişkeni temsil etmemizi sağlar.

...Sözdizimini merak ediyorsanız , buna Spread Operator denir ve buradan daha fazla bilgi edinebilirsiniz .

ES6 Array.from () kullanarak

Array.from kullanma :

function sortArgs() {
  return Array.from(arguments).sort(function (a, b) { return a - b; });
}

document.body.innerHTML = sortArgs(12, 4, 6, 8).toString();

Array.from Dizi benzeri veya Yinelenebilir nesneleri Dizi örneklerine dönüştürmeniz yeterlidir.



ES5

Aslında sadece kullanabilirsiniz Array'ın slicebir argümanlar nesne üzerinde işlev ve bir standart JavaScript diziye dönüştürür. Array'ın prototipi aracılığıyla buna manuel olarak başvurmanız yeterlidir:

function sortArgs() {
    var args = Array.prototype.slice.call(arguments);
    return args.sort();
}

Bu neden işe yarıyor? ECMAScript 5 belgelerinin bir alıntısı :

NOT : sliceİşlev kasıtlı olarak geneldir; bu değerinin bir Array nesnesi olmasını gerektirmez . Bu nedenle, bir yöntem olarak kullanılmak üzere diğer nesne türlerine aktarılabilir. İster slicefonksiyon, bir konak nesnesine başarıyla uygulanabilir uygulama bağlıdır.

Bu nedenle, uygun olan slicebir lengthözelliği olan her şey üzerinde çalışır arguments.


Eğer Array.prototype.sliceçok fazla sizin için bir lokma, sen biraz dizi değişmezleri kullanarak bu kısaltmak edebilirsiniz:

var args = [].slice.call(arguments);

Ancak, eski sürümün daha açık olduğunu hissetme eğilimindeyim, bunun yerine tercih ederim. Dizi gösterimini kötüye kullanmak, kibirli ve garip görünüyor.


5
Son Firefox sürümlerinde (2.0?) Ve ECMAScript 5'de, bunu biraz daha kolaylaştıran bir Array.slice yöntemi vardır. Buna şöyle derdiniz: var arge = Array.slice (argümanlar, 0) ;.
Matthew Crumley

9
Ne 0için? Geçmek istediğiniz hiçbir argüman olmadığından, neden sadece kullanmıyorsunuz var args = Array.prototype.slice.call(arguments);? [ MDC bağımsız değişkenleri sayfası ] ( developer.mozilla.org/en/JavaScript/Reference/… ), içermeyen yöntemi önerir 0.
Peter Ajtai

3
@Barney - sıralama gerekli çünkü asıl soru argümanları sıralamak istiyor. Sadece bir diziye dönüştürmek istiyorsanız, bu gerekli değildir.
13'te

17
"JavaScript motorlarında (örneğin V8) optimizasyonları engellediği için bağımsız değişkenleri dilimlememelisiniz." - MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
frameworkninja

3
Bunun orijinal soruya cevap verdiğinden emin değilim. Zaman geçti. Firefox ve Chrome'da ES6 denendiğinde, geri kalan parametre iyi bir alternatif haline geliyor - function sortArgs(...argsToSort) { return argsToSort.sort(); }MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Kir Kanos

40

Ayrıca, bu Bluebirdarguments , V8 JavaScript motoru altında işlevi en iyi hale getirecek şekilde nesnenin diziye nasıl yönetileceğini gösteren kitaplık wiki sayfasına söz veriyor :

function doesntLeakArguments() {
    var args = new Array(arguments.length);
    for(var i = 0; i < args.length; ++i) {
        args[i] = arguments[i];
    }
    return args;
}

Bu yöntem lehine kullanılır var args = [].slice.call(arguments);. Yazar ayrıca bir inşa adımının ayrıntı düzeyini azaltmaya nasıl yardımcı olabileceğini de gösterir.


2
+1 ve Bluebird Optimization Killer sayfasına bağlantı için teşekkürler. Not: Son zamanlarda bu optimizasyonun düğüm-thunkify projesinde kullanıldığını gördüm .
Yves M.

29
function sortArgs(){ return [].slice.call(arguments).sort() }

// Returns the arguments object itself
function sortArgs(){ return [].sort.call(arguments) }

Bazı dizi yöntemleri, hedef nesnenin gerçek bir dizi olmasını gerektirmeyecek şekilde tasarlanmıştır. Hedefin yalnızca uzunluk ve dizinler (sıfır veya daha büyük tamsayılar olmalıdır) adlı bir özelliğe sahip olmasını gerektirir .

[].sort.call({0:1, 1:0, length:2}) // => ({0:0, 1:1, length:2})

12

kullanın:

function sortArguments() {
  return arguments.length === 1 ? [arguments[0]] :
                 Array.apply(null, arguments).sort();
}

Array(arg1, arg2, ...) İadeler [arg1, arg2, ...]

Array(str1) İadeler [str1]

Array(num1)num1öğeleri olan bir dizi döndürür

Argüman sayısını kontrol etmelisiniz!

Array.slice sürüm (daha yavaş):

function sortArguments() {
  return Array.prototype.slice.call(arguments).sort();
}

Array.push sürümü (daha yavaş, dilimden daha hızlı):

function sortArguments() {
  var args = [];
  Array.prototype.push.apply(args, arguments);
  return args.sort();
}

Sürümü taşı (daha yavaş, ancak küçük boyut daha hızlı):

function sortArguments() {
  var args = [];
  for (var i = 0; i < arguments.length; ++i)
    args[i] = arguments[i];
  return args.sort();
}

Array.concat sürüm (en yavaş):

function sortArguments() {
  return Array.prototype.concat.apply([], arguments).sort();
}

1
Array.concat'daki düzleştirme davranışı nedeniyle dizi bağımsız değişkenlerini kabul edeceğini unutmayın. sortArguments (2, [3,0], 1) 0,1,2,3 değerini döndürür.
Hafthor

9

JQuery kullanıyorsanız, bence aşağıdakileri hatırlamak daha kolay:

function sortArgs(){
  return $.makeArray(arguments).sort();
}

1
Temelde saf JS'de aradığım şey bu, ancak jQuery'nin JS'yi grok için nasıl daha kolay hale getirdiğine dair sağlam bir örnek için +1.
Andrew Coleson

2
"Bir çerçeve / kütüphane için başka bir etiket de eklenmedikçe, saf bir JavaScript cevabı beklenir."
Michał Perłakowski

6

ECMAScript 6'da çirkin hack'lerin kullanılmasına gerek yoktur Array.prototype.slice(). Bunun yerine forma sözdizimini ( ...) kullanabilirsiniz .

(function() {
  console.log([...arguments]);
}(1, 2, 3))

Tuhaf görünebilir, ancak oldukça basit. Sadece argumentselemanlarını çıkarır ve diziye geri koyar. Hala anlamıyorsanız, aşağıdaki örneklere bakın:

console.log([1, ...[2, 3], 4]);
console.log([...[1, 2, 3]]);
console.log([...[...[...[1]]]]);

IE 11 gibi bazı eski tarayıcılarda çalışmadığını unutmayın, bu nedenle bu tarayıcıları desteklemek istiyorsanız Babel'i kullanmalısınız .


5

İşte kıyaslamaArgümanları diziye dönüştüren çeşitli yöntemlerin .

Bana gelince, az miktarda argüman için en iyi çözüm:

function sortArgs (){
  var q = [];
  for (var k = 0, l = arguments.length; k < l; k++){
    q[k] = arguments[k];
  }
  return q.sort();
}

Diğer durumlar için:

function sortArgs (){ return Array.apply(null, arguments).sort(); }

Kıyaslamalar için +1. Şu anda grafikler sortArgsFirefox'ta 6 kat daha hızlı, ancak en son Chrome'da iki kat daha yavaş olduğunu gösteriyor Array.apply.
joeytwiddle

1
Array.prototype.slice, JS V8 motor optimizasyonunu engellediği için kullanımdan kaldırıldığı için, ES6 yaygın olarak bulunana kadar bunu en iyi çözüm olarak görüyorum +1
Sasha

1
Ayrıca Array.slice () gibi Array jenerik yöntemleri de kullanımdan kaldırılmıştır
Sasha

4

Sondaki parametreleri bir diziye bağlayacak olan ECMAScript 6 spread operatörünü kullanmanızı öneririm . Bu çözüm ile argumentsnesneye dokunmanıza gerek kalmaz ve kodunuz basitleştirilir. Bu çözümün dezavantajı, çoğu tarayıcıda çalışmamasıdır, bunun yerine Babel gibi bir JS derleyicisi kullanmanız gerekecektir. Kaputun altında Babel arguments, for döngüsü olan bir Array'a dönüşür .

function sortArgs(...args) {
  return args.sort();
}

ECMAScript 6 kullanamıyorsanız, @Jonathan Fingland gibi diğer cevaplara bakmanızı tavsiye ederim

function sortArgs() {
    var args = Array.prototype.slice.call(arguments);
    return args.sort();
}

4

Lodash:

var args = _.toArray(arguments);

eylemde:

(function(){ console.log(_.toArray(arguments).splice(1)); })(1, 2, 3)

üretir:

[2,3]

6
Neden olmasın _.toArray?
Menixator

5
Ancak _.toArraydaha uygundur.
Menixator

_.Slice daha uygun olduğunu iddia ediyorum çünkü sık sık bazı önde gelen argümanları bırakmak istiyorsunuz.
Hafthor

4

Array.from()Dizi benzeri bir nesneyi (örneğin arguments) bağımsız değişken olarak alan ve diziye dönüştüren Use :

(function() {
  console.log(Array.from(arguments));
}(1, 2, 3));

IE 11 gibi bazı eski tarayıcılarda çalışmadığını unutmayın, bu nedenle bu tarayıcıları desteklemek istiyorsanız Babel'i kullanmalısınız .


3
function sortArg(){
var args = Array.from(arguments); return args.sort();
}

 function sortArg(){
    var args = Array.from(arguments); 
    return args.sort();
    }
 
 console.log(sortArg('a', 'b', 1, 2, '34', 88, 20, '19', 39, 'd', 'z', 'ak', 'bu', 90));


1

Başka Cevap.

Kara Büyüleri Kullan:

function sortArguments() {
  arguments.__proto__ = Array.prototype;
  return arguments.slice().sort();
}

Firefox, Chrome, Node.js, IE11 tamam.


6
Bu kesinlikle en iyi çözümdür ... eğer kodunuzu tamamen okunamaz hale getirmek istiyorsanız. Ayrıca, __proto__kullanımdan kaldırıldı. Bkz. MDN belgeleri .
Michał Perłakowski

1

Kullanmayı deneyin Object.setPrototypeOf()

Açıklama: Set prototypeof argumentsüzereArray.prototype

function toArray() {
  return Object.setPrototypeOf(arguments, Array.prototype)
} 

console.log(toArray("abc", 123, {def:456}, [0,[7,[14]]]))


Açıklama: argumentsÖğenin her dizinini ilgili dizinin dizinindeki bir diziye alın.

alternatif olarak kullanabilir Array.prototype.map()

function toArray() {
  return [].map.call(arguments, (_,k,a) => a[k])
} 

console.log(toArray("abc", 123, {def:456}, [0,[7,[14]]]))


Açıklama: argumentsÖğenin her dizinini ilgili dizinin dizinindeki bir diziye alın.

for..of döngü

function toArray() {
 let arr = []; for (let prop of arguments) arr.push(prop); return arr
} 

console.log(toArray("abc", 123, {def:456}, [0,[7,[14]]]))


veya Object.create()

Açıklama: Nesne oluşturun, nesnenin özelliklerini her dizindeki öğelere ayarlayın arguments; prototypeoluşturulan nesne kümesiArray.prototype

function toArray() {
  var obj = {};
  for (var prop in arguments) {
    obj[prop] = {
      value: arguments[prop],
      writable: true,
      enumerable: true,
      configurable: true
    }
  } 
  return Object.create(Array.prototype, obj);
}

console.log(toArray("abc", 123, {def: 456}, [0, [7, [14]]]))


Sen oldum insanlara sorarak "uzun yanıtlar" hakkında soru altında cevap tatmin olmadığını uyarı. Bana öyle geliyor ki cevabınızla ilgili asıl mesele, burada gösterdiğiniz yöntemlerden birini neden kullanmanız gerektiğini açıklamamanızdır . Önerdiğiniz çözümlerden herhangi birini kullanmamın bir yolu yok çünkü hepsi kabul edilen yanıttaki çözümlerden daha kötü. Örneğin, doc belgesine referansınız Object.setPrototypeOfbunun "çok yavaş bir işlem" olduğu konusunda uyarır. Bunu neden dünyada kullanayım Array.prototype.slice.call?
Louis

@Louis Her yaklaşım için açıklamalarla Güncellenmiş Yanıt. OP'deki soru "Standart kitaplığı kullanarak bunu yapmanın yerleşik bir yolu var mı?" Değil, "neden bir yöntemlerden herhangi kullanmalıdır" built-in? Yanıt gönderen herhangi bir kullanıcı, gönderilen çözümlerin OP için "doğru" olup olmadığını nasıl doğru bir şekilde belirleyebilir? Bunu belirlemek OP'ye kalmış gibi görünüyor? Aslında, bildirimin bu kısmı bu kullanıcıyla ilgilenen şeydir: "cevabınızın neden doğru olduğunu açıklayın" . Bu Soruya verilen Yanıtlardan herhangi biri şu durumu gösteriyor mu: "Bu cevap" doğru "çünkü: x, y, z"?
guest271314

Açıkladığım şey SO'nun nasıl çalıştığıdır. OP'nin bir çözümün neden diğerinden daha iyi olduğunu bilmek isteyip istemediği tamamen ilgisizdir, çünkü SO için gönderilen sorular öncelikle OP için değil, soruyu ve daha sonra cevaplarını okuyacak yüzlerce ve binlerce insan içindir. Ayrıca, cevaplar için oy kullanan kişilerin OP'nin tatmin olabileceği her şeye göre oy kullanmaları gerekli değildir.
Louis

1

İşte temiz ve özlü bir çözüm:

function argsToArray() {
  return Object.values(arguments);
}

// example usage
console.log(
  argsToArray(1, 2, 3, 4, 5)
  .map(arg => arg*11)
);

Object.values( )bir dizi olarak bir nesnenin değerlerini döndürür, ve o zamandan beri argumentsbir nesnedir, aslında dönüştürür argumentsböylelikle gibi bir dizinin yardımcı işlevlerini tüm sunmak, bir diziye map, forEach, filtervb


0

Benshmarck 3 yöntemleri:

function test()
{
  console.log(arguments.length + ' Argument(s)');

  var i = 0;
  var loop = 1000000;
  var t = Date.now();
  while(i < loop)
  {
      Array.prototype.slice.call(arguments, 0); 
      i++;
  }
  console.log(Date.now() - t);


  i = 0,
  t = Date.now();
  while(i < loop)
  {
      Array.apply(null, arguments);
      i++;
  }
  console.log(Date.now() - t);

  i = 0,
  t = Date.now();
  while(i < loop)
  {
      arguments.length == 1 ? [arguments[0]] : Array.apply(null, arguments);
      i++;
  }
  console.log(Date.now() - t);
}

test();
test(42);
test(42, 44);
test(42, 44, 88, 64, 10, 64, 700, 15615156, 4654, 9);
test(42, 'truc', 44, '47', 454, 88, 64, '@ehuehe', 10, 64, 700, 15615156, 4654, 9,97,4,94,56,8,456,156,1,456,867,5,152489,74,5,48479,89,897,894,894,8989,489,489,4,489,488989,498498);

SONUÇ?

0 Argument(s)
256
329
332
1 Argument(s)
307
418
4
2 Argument(s)
375
364
367
10 Argument(s)
962
601
604
40 Argument(s)
3095
1264
1260

Zevk almak !


1
arguments.length == 1?[arguments[0]]:Array.apply(null, arguments);Sadece bir tamsayı argümanı ile çağrılır dummyFn(3)ve sonuç neden olur[,,]
nevermind

@nevermind iyi iş, ben düzenleyin, sürümünüz daha iyi;) Ama bunun dummyFn(3)ne olduğunu anlamıyorum ? bu işlev mevcut değil ...
Matrix

Uh ... boş ver, sadece bir örnek bir fonksiyonun sadece bir tamsayı argümanı ile çağrıldığını ve İngilizcem için özür dilerim.
nevermind

0

function sortArgs(...args) {
  return args.sort(function (a, b) { return a - b; });
}

document.body.innerHTML = sortArgs(1, 2, 3, 4).toString();


0

Dinlenme parametreleri iyi çalışıyor olsa da, argumentsherhangi bir nedenle kullanmaya devam etmek istiyorsanız ,

function sortArgs() {
  return [...arguments].sort()
}

[...arguments] bir çeşit alternatif olarak düşünülebilir Array.from(arguments)mükemmel bir şekilde çalışan .

ES7 alternatifi bir dizi kavramadır:

[for (i of arguments) i].sort()

Sıralamadan önce argümanları işlemek veya filtrelemek istiyorsanız bu en kolay olabilir:

[for (i of arguments) if (i % 2) Math.log(i)].sort()

0
 function x(){
   var rest = [...arguments]; console.log(rest);return     
   rest.constructor;
 };
 x(1,2,3)

Basit yıkım tekniğini denedim


0

Bağımsız Değişkenler nesnesi yalnızca bir işlev gövdesi içinde kullanılabilir. Arguments Nesnesini bir dizi gibi dizine ekleyebilmenize rağmen, bu bir dizi değildir. Uzunluk dışında herhangi bir dizi özelliği yoktur.

// function arguments length 5
function properties(a,b,c,d,e){
var function_name= arguments.callee.name
var arguments_length= arguments.length;
var properties_length=  properties.length; 
var function_from= properties.caller.name;
console.log('I am the function name: '+ function_name);
console.log('I am the function length, I am function spacific: '+ properties_length); 
console.log('I am the arguments length, I am context/excution spacific: '+ arguments_length);
console.log('I am being called From: '+  function_from );
}

// arguments 3
function parent(){
properties(1,2,3);
}

//arguments length 3 because execution spacific
parent();

Bu örnekte gördüğünüz gibi bir dizi gibi dizine eklenebilse de:

function add(){

var sum=0;

for(var i=0; i< arguments.length;i++){

sum = sum + arguments[i];

}

return sum;

}

console.log(add(1,2,3));

Ancak, Arguments nesnesi bir dizi değildir ve uzunluk dışında başka bir özelliği yoktur.

Arguments nesnesini, Arguments nesnesine erişebileceğiniz bir diziye dönüştürebilirsiniz.

Bir işlev gövdesi içindeki arguments nesnesine erişmenin birçok yolu vardır ve bunlar şunları içerir:

  1. Array.prototoype.slice.call yöntemini çağırabilirsiniz.

Array.prototype.slice.call (bağımsız)

function giveMeArgs(arg1,arg2){

var args = Array.prototype.slice.call(arguments);
return args
}

console.log( giveMeArgs(1,2));

  1. değişmez diziyi kullanabilirsiniz

[] .Slice.call (bağımsız).

function giveMeArgs(arg1,arg2){

var args = [].slice.call(arguments);

return args;

}

console.log( giveMeArgs(1,2) );

  1. Geri Kalanı kullanabilirsiniz ...

function giveMeArgs(...args){

return args;

}

console.log(giveMeArgs(1,2))

  1. forma kullanabilirsiniz [...]

function giveMeArgs(){

var args = [...arguments];
return args;

}

console.log(giveMeArgs(1,2));

  1. Array.from () kullanabilirsiniz

function giveMeArgs(){

var args = Array.from(arguments);

return args;

}

console.log(giveMeArgs(1,2));


0

Herhangi bir argümanla yapmak için yeniden kullanılabilir bir fonksiyon oluşturabilirsiniz, en basit olanı şuna benzer:

function sortArgs() {
  return [...arguments].sort();
}

sortArgs('ali', 'reza', 1, 2, 'a'); //[1, 2, "a", "ali", "reza"];

Spread sözdizimi ES6 ve üzeri sürümlerde kullanılabilir ...

Ancak ES5 ve daha düşük bir sürümle uyumlu bir şey kullanmak isterseniz, kullanabilirsiniz Array.prototype.slice.call, böylece kod şöyle görünür:

function sortArgs() {
  return Array.prototype.slice.call(arguments).sort();
}

sortArgs('ali', 'reza', 1, 2, 'a'); //[1, 2, "a", "ali", "reza"];

Bunu yapmanın başka birkaç yolu daha var, örneğin Array.from, argümanları kullanmak veya döngüler arasında dolaşmak ve bunları yeni bir diziye atamak için ...


-2

Bu çok eski bir soru, ama bence önceki çözümlerden biraz daha kolay ve harici kütüphanelere dayanmayan bir çözümüm var:

function sortArguments() {
  return Array.apply(null, arguments).sort();
}

2
Array.applyyalnızca tek bir pozitif tam sayı argümanınız varsa çalışmaz. Bunun nedeni new Array(3), bir dizi uzunluğu oluşturmasıdır 3. Daha spesifik olmak gerekirse, sonuç olacaktır [undefined, undefined, undefined]ve olmayacaktır [3].
inf3rno
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.