English 中文(简体)
A question about JavaScript s slice and splice methods
原标题:

I came across the following code:

var f = function () {
    var args = Array.prototype.slice.call(arguments).splice(1);

    // some more code 
};

Basically, the result in args is an array that is a copy of the arguments without its first element.

But what I can t understand exactly is why f s arguments (which is an object that holds the function s inputted arguments into an array-like object) object is being passed to the slice method and how slice(1) is removing the first element (positioned at index 0).

Can anyone please explain it for me?

P.S. The code is from this partial application function

最佳回答

<Note>
The actual code from that linked answer is:

var args = Array.prototype.slice.call(arguments, 1);

i.e. "slice", not "splice"
</Note>

First of all, the slice method is often used to make a copy of the array it s called on:

var a = [ a ,  b ,  c ];
var b = a.slice();  // b is now a copy of a
var c = a.slice(1); // c is now [ b ,  c ]

So the short answer is that the code is basically emulating:

arguments.slice(1); // discard 1st argument, gimme the rest

However you can t do that directly. The special arguments object (available inside the execution context of all JavaScript functions), although Array-like in that it supports indexing via the [] operator with numeric keys, is not actually an Array; You can t .push onto it, .pop off it, or .slice it, etc.

The way the code accomplishes this is by "tricking" the slice function (which again is not available on the arguments object) to run in the context of arguments, via Function.prototype.call:

Array.prototype.slice // get a reference to the slice method
                      // available on all Arrays, then...
  .call(              // call it, ...
    arguments,        // making "this" point to arguments inside slice, and...
    1                 // pass 1 to slice as the first argument
  )

Array.prototype.slice.call(arguments).splice(1) accomplishes the same thing, but makes an extraneous call to splice(1), which removes elements from the array returned from Array.prototype.slice.call(arguments) starting at index 1 and continuing to the end of the array. splice(1) doesn t work in IE (it s technically missing a 2nd parameter telling it how many items to remove that IE and ECMAScript require).

问题回答
var args = Array.prototype.slice.call(arguments).splice(1);

First takes a copy of arguments(*), then removes all but the first item from it (in a non-standard way), and assigns those items being removed to args.

The extra array being produced, then altered and thrown away is quite redundant. It would be better to say — as the version in the answer you linked to indeed does:

var args = Array.prototype.slice.call(arguments, 1);

Partial function application is also a feature of the function.bind method, being standardised by ECMAScript Fifth Edition. Until browsers have implemented it, you can pick up an a fallback JS-native version from the bottom of this answer.

*: array.slice() is the normal idiom for copying an array, and array.slice(1) for taking the tail. It has it be called explicitly through the Array.prototype because arguments is not an Array, even though it looks just like one, so doesn t have the normal array methods. This is another of JavaScript s weird mistakes.

You quite often see people using the Array.prototype methods on objects that aren t Arrays; the ECMAScript Third Edition standard goes out of its way to say this is OK to do for the arguments array-like, but not that you may also do it on other array-likes that may be host objects, such as NodeList or HTMLCollection. Although you might get away with calling Array.prototype methods on a non-Array in many browsers today, the only place it is actually safe to do so is on arguments.

The returned value of a splice is an array of the elements that were removed, but the original array (or array-like object), is truncated at the splice index.

Making a copy with slice preserves the original arguments array, presumably for use later in the function.

In this case the same result can be had with args = [].slice.call(arguments, 1)

function handleArguments(){
 var A= [].slice.call(arguments).splice(1);
 //arguments is unchanged
 var s=  A= +A+ 
arguments.length= +arguments.length;

 var B= [].splice.call(arguments, 1);
 // arguments now contains only the first parameter
 s+=  

B= +B+ 
arguments.length= +arguments.length;
 return s;
}

// test
alert(handleArguments(1, 2, 3, 4));

returned value:
//var A= [].slice.call(arguments).splice(1);
A=2,3,4
arguments.length=4

//var B= [].splice.call(arguments, 1);
B=2,3,4
arguments.length=1




相关问题
selected text in iframe

How to get a selected text inside a iframe. I my page i m having a iframe which is editable true. So how can i get the selected text in that iframe.

How to fire event handlers on the link using javascript

I would like to click a link in my page using javascript. I would like to Fire event handlers on the link without navigating. How can this be done? This has to work both in firefox and Internet ...

How to Add script codes before the </body> tag ASP.NET

Heres the problem, In Masterpage, the google analytics code were pasted before the end of body tag. In ASPX page, I need to generate a script (google addItem tracker) using codebehind ClientScript ...

Clipboard access using Javascript - sans Flash?

Is there a reliable way to access the client machine s clipboard using Javascript? I continue to run into permissions issues when attempting to do this. How does Google Docs do this? Do they use ...

javascript debugging question

I have a large javascript which I didn t write but I need to use it and I m slowely going trough it trying to figure out what does it do and how, I m using alert to print out what it does but now I ...

Parsing date like twitter

I ve made a little forum and I want parse the date on newest posts like twitter, you know "posted 40 minutes ago ","posted 1 hour ago"... What s the best way ? Thanx.

热门标签