2

In the context of inside a function, here's the code (based on the standard pattern of making a function's 'arguments' into an array):

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

I'm trying to study this out (am a beginner at JavaScript, coming from C#).

I understand that slice is an instance method due to it being a prototype function of Array.

I also understand that this is not a static 'utility function', meaning to use it, you have to new it up like so: (example) var myArray = new Array(); myArray.slice(...);

call passes an object in here to change the context to that of arguments

Related to this, I don't also know the difference between Array.prototype.slice.call([32,32,121,412]) and Array.prototype.slice([32,32,121,412]) not in the context of call.

So, here's my question:

I just don't get how this works in relation to instance vs static methods... so can anyone explain the intricacies of var args = Array.prototype.slice.call(arguments);?

Why can this be used without calling new?

Why was this possible? It's not a Static method, and it must be 'newed' up, and it only works when you use call function... (at least in my C# mentality...)

Jan Carlo Viray
  • 11,856
  • 11
  • 42
  • 63
  • See here http://stackoverflow.com/questions/5145032/whats-the-use-of-array-prototype-slice-callarray-0 – xdazz Feb 07 '12 at 02:50
  • possible duplicate of [how does Array.prototype.slice.call() work?](http://stackoverflow.com/questions/7056925/how-does-array-prototype-slice-call-work) –  Feb 07 '12 at 02:53
  • @xdazz: same code, but not same contextual question.. he's asking why, i'm asking how this happens.. – Jan Carlo Viray Feb 07 '12 at 02:54
  • @JanCarloViray Because `Array.prototype` is also an object which is the prototype of Array. – xdazz Feb 07 '12 at 02:56
  • @amnotiam: same code, but not same question.. mine is based on why can this be used WITHOUT INSTANTIATING a new array (ie: using 'new') – Jan Carlo Viray Feb 07 '12 at 02:56
  • @JanCarloViray: Well, that's what the question I linked answers... but whatever. –  Feb 07 '12 at 03:43

4 Answers4

1

The difference between Array.prototype.slice.call([32, 32, 121, 412]) and Array.prototype.slice([32, 32, 121, 412]) is that in the first case, the actual Array [32, 32, 121, 412] becomes the "this" object for the call. In other words, it's just like this code: [32, 32, 121, 412].slice(). Just calling slice on the prototype executes it in the context of the prototype object, which probably wouldn't do anything useful.

Jacob
  • 77,566
  • 24
  • 149
  • 228
  • thanks. that's just a part of my question.. mind if you could explain to me why this (var args = Array.prototype.slice.call(arguments)) was possible to use without using "new" and instead just using "call"? – Jan Carlo Viray Feb 07 '12 at 02:52
  • 1
    An `Array` literal like `[32, 32, 121, 412]` is a "new" object. It's just like saying `new Array(32, 32, 121, 412)`. – Jacob Feb 07 '12 at 03:15
  • thanks. but what I meant was that .slice is an instance method (prototype), usually needing to be 'new'ed up, but why was this possible here? ie: shouldn't it be var myArray = []; myArray.slice(arguments)?? ... i just don't get how it was possible to call a static object like an array without 'new'ing it up... – Jan Carlo Viray Feb 07 '12 at 03:17
  • 1
    I think you misunderstand what `call` does. The first parameter to `call` is the object to use as the `this` object, so you're in effect calling `slice` *on the array argument*. – Jacob Feb 07 '12 at 03:25
1

When you add a function to an object's prototype, it becomes a function that you can use on instances of that object. The context of that function with be the instance. i.e.

Array.prototype.myFunction = function() {
     alert( this[0] ); // this should refer to the Array instance
};
var x = new Array(1);
x[0] = 5;
x.myFunction(); // alerts 5

However, sometimes you may have a structure like an array that are not a subclass or instance of Array (such as an Arguments object). What the call method of a function does is changes the context to whatever the first parameter to call is. In this case, the call method is being called on a function of the Array's prototype. In all reality, Array.prototype.myFunction is just a function defined in the above block of code. call is a method that can be called on any function to change its context. Therefore, instead of an Array instance as the context, you would have an arguments object.

function foo() {
    Array.prototype.myFunction.call( arguments ); // arguments is [6]
    // alerts 6
}
foo( 6 );

More info on call.

Will
  • 19,661
  • 7
  • 47
  • 48
1

I think perhaps you're getting confused by the behaviour of "instance" and "static" methods in languages like Java that have classes. JavaScript doesn't work the same way.

Also you're confused about another issue, that being how all JS function calls work in terms of setting this within the called function (i.e., setting what object the function will likely attempt to operate on) and what effect .call() has on setting this.

The .slice() method is defined as a property of Array.prototype, not as a Java-style "instance method" on the individual array instances. You can call Array.prototype.slice() without needing an instance of an array created with new.

When you say:

myArray.slice()

JS will first see if .slice() actually is a method of the myArray object, and then (given that it isn't) it will see if it is a method of the Array prototype - which it is, so it runs that method.

When you call any JS function with "dot" notation, i.e., myArray.slice(), within that function the special variable this will be set to the object. this is a reference to the object that the function should operate on. But if you call a JS function using .call(), within that function this will be set to the object you pass as a parameter to .call(). So

myArray.slice()

says to call .slice() and have it operate on myArray.

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

Says to call .slice() and have it operate on arguments

P.S. don't use var myArray = new Array(); - better to say var myArray = [];

nnnnnn
  • 147,572
  • 30
  • 200
  • 241
  • ..so, you're saying that there are no 'instance' (need to 'new' it) or 'static' methods in JavaScript? (i'm a bit confused.. just barely moving from C# to JS) – Jan Carlo Viray Feb 07 '12 at 03:03
  • ..also can you expand on what you said "Also you're confused about another issue, that being how all JS function calls work in terms of setting this within the called function"? :) – Jan Carlo Viray Feb 07 '12 at 03:15
  • 1
    JavaScript is OO, but not the same flavour of OO as C# or Java. You need to stop thinking about "classes" where the terms "instance method" and "static method" apply, and start thinking about object prototypes. JavaScript _can_ have "instance" methods in the sense of needing to create an object using `new ConstructorName()` before using them. It can also have methods defined on an object's prototype where all instances will have access but also you can call any prototype methods directly like your `Array.prototype.slice()` example. – nnnnnn Feb 07 '12 at 03:18
  • ohhh.. well thank you Mr. nnnnnn :) that does make sense now. Will definitely study it out more and change my paradigm. Thanks for a GREAT answer and your time. – Jan Carlo Viray Feb 07 '12 at 03:20
  • 1
    JavaScript's `this` keyword works radically differently to `this` in C# or Java. JS functions are themselves objects. Read through this page: https://developer.mozilla.org/en/JavaScript/Guide/Working_with_Objects. – nnnnnn Feb 07 '12 at 03:21
0

Unlike C#/Java, functions are actually first-class citizens in JavaScript.

In a general sense:

This means there is no need to "new" it up.. it works exactly as it is because it is its own object.

"new"ing up a function (in a general sense) merely changes the 'this' value of that function to the variable it will be assigned to, then returns it.

It is possible to use a function in JavaScript without "newing" it up because they are "first-class citizens" in JavaScript.

In a more in-depth sense, this is what "new" does:
- it creates a new object deriving from MyConstructor.prototype
- it assigns the 'this' value of the constructor function to the new object
- execute the code inside (adds properties to new object/instance)
- returns the new object

Some extra notes about what I learned from instances:
- they don't have a .prototype property like their constructor functions
- though they have a [[prototype]] property, derived from MyConstructor.prototype
- overriding a property in the instance shadows the MyConstructor.prototype[property]..

Jan Carlo Viray
  • 11,856
  • 11
  • 42
  • 63
  • Using `new` doesn't "merely change the 'this' value", it creates a new object _with the appropriate prototype_, sets `this` to that object, and then the function will return that object. JavaScript uses prototype-based inheritance rather than class-based inheritance like C# or Java, but still `new` is essential for that purpose. – nnnnnn Feb 26 '12 at 21:25
  • thanks for the comment. yeah in a more in-depth sense, 'new' does create a new object deriving from its MyConstructor.prototype (includes .constructor & .__proto__ (non-standard)), sets 'this' to that object, and then it returns it.. thanks for adding to this. – Jan Carlo Viray Feb 26 '12 at 23:30