8

Consider this piece of code, with console output at the end of each line:

function whatever() {
  console.log(arguments) // { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }
  console.log(Array.prototype.slice.call(arguments)) // [ 1, 2, 3, 4, 5 ]
  console.log(Array.prototype.slice.call({ '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 })) // []
}

whatever(1,2,3,4,5)

Why is it that the third console.log outputs an empty array?

3 Answers 3

13

Because in order for Array.prototype.slice to work, you need to pass an array-like object. And in order for an object to fit that category, it needs a length property, which your object doesn't have. Try this:

var arr = { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 };
arr.length = 5;
var res = Array.prototype.slice.call(arr);
console.log(res);

FIDDLE

Sign up to request clarification or add additional context in comments.

4 Comments

Instead of assigning length in such way, maybe would be better if you get enumerable keys length arr.length = Object.keys(arr).length
@Givi I agree. But to be even closer to the actual behavior of an array, you would have to set the length property to the highest numerical key plus one. arr.length = Object.keys(arr).filter(function(item){return /^[0-9]+$/.test(item);}).sort(function(a,b){return b-a})[0] + 1;. Anyway, it was just an example to show that it works, as long as you have the length property set correctly :)
Beautiful solution, but sort is useless in that case, I think so ;) and sort(...)[0] + 1; is same as "4" + 1 that equals 41. And maybe you should get length after filtering, filter(...).length, and even array-like object is not sorted while slicing it'll be sorted as it should ;) And even in object is other properties like "someProperty" : "some value", they will not be added while slicing.
@Givi You're right, you need to convert the key to a number before adding 1. I missed that. But you still would have to sort it I think, since you don't want the number of keys but the highest key. If you have the keys 0,1,3 you want the length to be 4, as it would be in a real array. And yes, non-numerical properties will not be added, when you silce it. But you calculate the length before you slice and therefore you have to filter them out.
2

As @basilikum described, this is because .length is required in order to use .slice(). To understand why it's required, imagine that you were writing your own version of Array.prototype.slice() after reading the MDN docs:


Syntax

Array.slice(begin[, end])

Parameters

begin

Zero-based index at which to begin extraction.

As a negative index, begin indicates an offset from the end of the sequence. slice(-2) extracts the second-to-last element and the last element in the sequence.

end

Zero-based index at which to end extraction. slice extracts up to but not including end.

slice(1,4) extracts the second element through the fourth element (elements indexed 1, 2, and 3).

As a negative index, end indicates an offset from the end of the sequence. slice(2,-1) extracts the third element through the second-to-last element in the sequence.

If end is omitted, slice extracts to the end of the sequence.


To handle all those cases and a few more not listed, your code would have to be something along these lines (this may have bugs but should be close):

Array.prototype.myslice = function( begin, end ) {
    // Use array length or 0 if missing
    var length = this.length || 0;
    // Handle missing begin
    if( begin === undefined ) begin = 0;
    // Handle negative begin, offset from array length
    if( begin < 0 ) begin = length + begin;
    // But make sure that didn't put it less than 0
    if( begin < 0 ) begin = 0;
    // Handle missing end or end too long
    if( end === undefined  ||  end > length ) end = length;
    // Handle negative end (don't have to worry about < 0)
    if( end < 0 ) end = length + end;
    // Now copy the elements and return resulting array
    var result = [];
    for( var i = begin;  i < end;  ++i )
        result.push( this[i] );
    return result;
};

That's why .slice() requires this.length—you wouldn't be able to write the function without it.

Comments

0

As much as i have knowledge

Argument is a variable of object type which we can use to get entry for every argument passed to a method

for example if we use this

whatever(a,b,c)

argument will return some thing like 0:a ,1:b ,2:c

and slice method is used to slice an array from a starting point to end point like

var myarray=["1","2","3","4"];
myarray.slice(2,3);

will return 3 and 4 as they exist on index 2 and 3

so if u want to use slice on your arguments just define it like slice(startindex,endindex);

just an edit slice.call is used to convert an array type to another array type data structure and in your case while passing arguments as it is a known type for javascript engine it considers it as an array type and simply converts it but hardcoding an array doesn't seems to work (just a thought).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.