Argümanları gerçek bir dizi yapmak için kullanıldığını biliyorum, ama kullanırken ne olduğunu anlamıyorum Array.prototype.slice.call(arguments)
Argümanları gerçek bir dizi yapmak için kullanıldığını biliyorum, ama kullanırken ne olduğunu anlamıyorum Array.prototype.slice.call(arguments)
Yanıtlar:
Kaputun altında olan şey, .slice()
normal olarak adlandırıldığında this
bir Array olmasıdır ve daha sonra sadece bu Array üzerinde yinelenir ve işini yapar.
Nasıl this
içinde .slice()
Dizi fonksiyonu? Çünkü bunu yaptığınızda:
object.method();
... object
otomatik değeri olur this
içinde method()
. Böylece:
[1,2,3].slice()
... [1,2,3]
Dizi değeri olarak ayarlanır this
içinde .slice()
.
Peki ya this
değer olarak başka bir şeyi değiştirebilseydiniz ? .length
Yerine koyduğunuz her şey bir sayısal özelliğe ve sayısal dizinler olan bir grup özelliğe sahip olduğu sürece, çalışmalıdır. Bu tür nesnelere genellikle dizi benzeri nesne denir .
.call()
Ve .apply()
yöntemleri izin elle değerini ayarlamak this
bir işlevde. Biz değerini ayarlamak Yani eğer this
içinde .slice()
bir dizi benzeri nesne , .slice()
sadece edecek varsaymak bir Array birlik olduğuna ve bunun şeyi yapacaktır.
Bu düz nesneyi örnek olarak alalım.
var my_object = {
'0': 'zero',
'1': 'one',
'2': 'two',
'3': 'three',
'4': 'four',
length: 5
};
Bu açıkça bir Array değildir, ancak this
değerini olarak ayarlayabilirseniz .slice()
, o zaman işe yarayacaktır, çünkü .slice()
düzgün çalışmak için bir Array gibi görünüyor .
var sliced = Array.prototype.slice.call( my_object, 3 );
Örnek: http://jsfiddle.net/wSvkv/
Konsolda görebileceğiniz gibi, sonuç beklediğimiz şeydir:
['three','four'];
Dolayısıyla, bir arguments
nesneyi this
değeri olarak ayarladığınızda bu olur .slice()
. Çünkü arguments
bir .length
özelliği ve bir dizi sayısal endeksi vardır, .slice()
sadece gerçek bir Array üzerinde çalışıyormuş gibi işine devam eder.
Array.prototype.slice
yöntem tanımı.
for-in
Siparişi garanti etmeyen açıklama. Tarafından kullanılan algoritma , verilen nesnenin (veya Dizi veya herhangi biriyle) .slice()
başlayan 0
ve onunla biten (içermeyen) sayısal bir sıra tanımlar .length
. Böylece, siparişin tüm uygulamalarda tutarlı olması garanti edilir.
var obj = {2:"two", 0:"zero", 1: "one"}
. for-in
Nesneyi numaralandırmak için kullanırsak , düzen garantisi yoktur. Kullandığımız Ama eğer for
, elle zorlayabilir: for (var i = 0; i < 3; i++) { console.log(obj[i]); }
. Artık nesnenin özelliklerine, for
döngümüz tarafından tanımladığımız artan sayısal sırayla ulaşılacağını biliyoruz . İşte .slice()
böyle. Gerçek bir Dizisi olup olmadığı önemli değildir. Sadece başlar 0
ve yükselen bir döngüdeki özelliklere erişir.
arguments
Nesne aslında bir Array örneğidir değildir ve Dizi yöntemlerden herhangi yoktur. Bu nedenle, arguments.slice(...)
arguments nesnesinin dilim yöntemi olmadığından çalışmaz.
Diziler bu yönteme sahiptir ve arguments
nesne bir diziye çok benzediğinden ikisi uyumludur. Bu, arguments nesnesiyle dizi yöntemlerini kullanabileceğimiz anlamına gelir. Dizi yöntemleri diziler düşünülerek oluşturulduğundan, diğer argüman nesneleri yerine diziler döndürürler.
Peki neden kullanıyorsunuz Array.prototype
? Array
Biz (yeni diziler oluşturmak amacı new Array()
) ve bu yeni diziler dilim gibi, yöntemleri ve özellikleri geçirilir. Bu yöntemler [Class].prototype
nesnede saklanır . Yani, verimlilik uğruna, (new Array()).slice.call()
veya tarafından dilim yöntemine erişmek yerine, [].slice.call()
doğrudan prototipten alıyoruz. Bu yüzden yeni bir dizi başlatmak zorunda değiliz.
Ama neden ilk etapta bunu yapmalıyız? Dediğiniz gibi, bir argüman nesnesini Array örneğine dönüştürür. Ancak dilimi kullanmamızın sebebi her şeyden çok "hack'tir". Dilim yöntemi, bir dizinin dilimini a tahmin edersiniz ve bu dilimi yeni bir dizi olarak döndürür. Hiçbir argümanın iletilmemesi (bağlam olarak arguments nesnesinin yanı sıra) dilim yönteminin iletilen "dizi" nin (bu durumda arguments nesnesi) tam bir parçasını almasına ve yeni bir dizi olarak döndürmesine neden olur.
Normalde
var b = a.slice();
diziyi a
içine kopyalar b
. Ancak yapamayız
var a = arguments.slice();
çünkü arguments
gerçek bir dizi değildir ve slice
yöntem olarak yoktur. Array.prototype.slice
, slice
dizilerin call
işlevidir ve işlevi olarak this
ayarlı olarak çalıştırır arguments
.
prototype
? slice
yerel bir Array
yöntem değil mi?
Array
bir yapıcı işlevi olduğu ve karşılık gelen "sınıfı" dir Array.prototype
. Ayrıca kullanabilirsiniz[].slice
slice
her Array
örneğin bir yöntemidir , ancak Array
yapıcı işlevi değildir . Sen kullanmak prototype
bir şantiye teorik örneklerinin erişim yöntemlerine ilişkindir.
İlk olarak, işlev çağırma işleminin JavaScript'te nasıl çalıştığını okumalısınız . Sorunuzu cevaplamak için tek başına yeterli olduğundan şüpheleniyorum. Ama işte neler olduğuna dair bir özet:
Array.prototype.slice
özler yöntemi ile ilgili 'in prototip . Ancak doğrudan çağırmak işe yaramaz, çünkü bu bir yöntemdir (işlev değil) ve bu nedenle bir bağlam (çağıran bir nesne ) gerektirir, aksi takdirde fırlar .slice
Array
this
Uncaught TypeError: Array.prototype.slice called on null or undefined
call()
Yöntem temelde bu iki çağrıları eşdeğer hale bir yöntemin bağlamı belirlemenizi sağlar:
someObject.slice(1, 2);
slice.call(someObject, 1, 2);
Birincisi dışında slice
yöntemin someObject
prototip zincirinde (olduğu gibi Array
) var olmasını gerektirirken, ikincisi bağlamın ( someObject
) yönteme manuel olarak geçirilmesine izin verir .
Ayrıca, ikincisi kısadır:
var slice = Array.prototype.slice;
slice.call(someObject, 1, 2);
Hangisi ile aynı:
Array.prototype.slice.call(someObject, 1, 2);
// We can apply `slice` from `Array.prototype`:
Array.prototype.slice.call([]); //-> []
// Since `slice` is available on an array's prototype chain,
'slice' in []; //-> true
[].slice === Array.prototype.slice; //-> true
// … we can just invoke it directly:
[].slice(); //-> []
// `arguments` has no `slice` method
'slice' in arguments; //-> false
// … but we can apply it the same way:
Array.prototype.slice.call(arguments); //-> […]
// In fact, though `slice` belongs to `Array.prototype`,
// it can operate on any array-like object:
Array.prototype.slice.call({0: 1, length: 1}); //-> [1]
Array.prototype.slice.call (bağımsız değişkenler), bağımsız değişkenleri bir diziye dönüştürmenin eski yoludur.
ECMAScript 2015'te Array.from veya forma operatörünü kullanabilirsiniz:
let args = Array.from(arguments);
let args = [...arguments];
Çünkü MDN notları
Arguments nesnesi bir dizi değildir. Bir diziye benzer, ancak uzunluk dışında herhangi bir dizi özelliği yoktur. Örneğin, pop yöntemi yoktur. Ancak, gerçek bir diziye dönüştürülebilir:
Burada slice
yerel nesneyi çağırıyoruz Array
, uygulanmasını değil ve bu yüzden ekstra.prototype
var args = Array.prototype.slice.call(arguments);
Unutmayın, bu davranışın düşük seviyeli temelleri tamamen JS motoruna entegre edilen tür dökümdür.
Dilim yalnızca nesneyi alır (varolan arguments.length özelliği sayesinde) ve bu işlemin ardından yapılan dizi nesnesini döndürür.
String yöntemini bir INT değeriyle tedavi etmeye çalışırsanız test edebileceğiniz aynı mantık:
String.prototype.bold.call(11); // returns "<b>11</b>"
Bu da yukarıdaki ifadeyi açıklıyor.
slice
Dizilerin sahip olduğu yöntemi kullanır ve onu nesne this
olarak çağırır arguments
. Bu , böyle bir yöntem olduğunu arguments.slice()
varsaymış arguments
gibi adlandırdığınız anlamına gelir .
Herhangi bir argüman olmadan bir dilim oluşturmak tüm öğeleri alacaktır - böylece elemanları arguments
bir diziye kopyalar .
Varsayalım: function.apply(thisArg, argArray )
Apply yöntemi, buna bağlanacak nesneyi ve isteğe bağlı bir argüman dizisini ileten bir işlevi çağırır.
Slice () yöntemi bir dizinin bir bölümünü seçer ve yeni diziyi döndürür.
Yani Array.prototype.slice.apply(arguments, [0])
dizi çağırdığınızda argümanlarda dilim yöntemi çağrılır (bağlanır).
Belki biraz geç, ama tüm bu karışıklığın cevabı, JS'de miras için call () yönteminin kullanılmasıdır. Örneğin bunu Python veya PHP ile karşılaştırırsak, çağrı sırasıyla super () olarak kullanılır. içinde () veya parent :: _ construct ().
Bu, kullanımını netleştiren kullanımına bir örnektir:
function Teacher(first, last, age, gender, interests, subject) {
Person.call(this, first, last, age, gender, interests);
this.subject = subject;
}
Referans: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance
.slice () normal olarak çağrıldığında, bu bir Dizi'dir ve daha sonra sadece bu Dizi üzerinde yinelenir ve çalışmasını yapar.
//ARGUMENTS
function func(){
console.log(arguments);//[1, 2, 3, 4]
//var arrArguments = arguments.slice();//Uncaught TypeError: undefined is not a function
var arrArguments = [].slice.call(arguments);//cp array with explicity THIS
arrArguments.push('new');
console.log(arrArguments)
}
func(1,2,3,4)//[1, 2, 3, 4, "new"]
Bunu kendime hatırlatmak için yazıyorum ...
Array.prototype.slice.call(arguments);
== Array.prototype.slice(arguments[1], arguments[2], arguments[3], ...)
== [ arguments[1], arguments[2], arguments[3], ... ]
Ya da çoğu şeyi bir diziye dönüştürmek için bu kullanışlı $ A işlevini kullanın .
function hasArrayNature(a) {
return !!a && (typeof a == "object" || typeof a == "function") && "length" in a && !("setInterval" in a) && (Object.prototype.toString.call(a) === "[object Array]" || "callee" in a || "item" in a);
}
function $A(b) {
if (!hasArrayNature(b)) return [ b ];
if (b.item) {
var a = b.length, c = new Array(a);
while (a--) c[a] = b[a];
return c;
}
return Array.prototype.slice.call(b);
}
örnek kullanım ...
function test() {
$A( arguments ).forEach( function(arg) {
console.log("Argument: " + arg);
});
}