"this" keyword


#1

I’m trying to learn JS from scratch, and I using JavaScript Absolute Beginner’s Guide - 1st Ed (2016) as reference. That is how I came to know of Kirupa and this forum. So far I’ve reached the topic Extending Built-In Objects Is Controversial, Chapter 17 Page No.186. There’s an example where the behavior of slice() is changed,

Array.prototype.slice = function() {
  var input = this;
  input[0] = "This is an awesome example!";
  return input;
}
var tempArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
tempArray.slice();
alert(tempArray);

The use of “This” was explained prior to this topic and what I’ve understood is that “This” always points to an object and it’s used as a pronoun in place of the object in use.

How does it work here though?

var input = this;

What does that declaration imply? What does input hold here? What does “This” hold or point to?


#2

In this case, this refers to the tempArray object you are calling slice via. @senocular posted a great answer a while ago about what the this keyword points to in various situations, but I can’t seem to find it right now!


#3

Oi, yeah I wonder which one you’re thinking of. I’ve written so many :slight_smile:

To add on to what @kirupa has said, this represents some value that the current function or scope is considering its context. Its just another variable (of sorts), like a function argument, that gets set to some value based on a certain set of rules. For functions, you can very much think of it a lot like another argument, one hidden from you in the parameter list but exists all the same and always has the name “this”

There are a lot of rules about what this is given certain circumstances, but the main rule is this: when a function is called from an object, the context - that is the value of this when that function gets executed - gets set to the object from which the function is called. So given:

tempArray.slice();

The function slice is getting called with the context of tempArray because that’s the object from which the function was referenced. Basically, look at the function call and walk one dot (or one set of brackets ([])) back from there. That object is your this.

Now, once inside the body of slice you can use this to represent tempArray - or any other object that may have called slice for that particular invocation. That’s the power of this. It can be anything, all depending on who called it and not locked to a single variable like it would if you used tempArray directly within slice.

tempArray.slice(); // this is tempArray
otherArray.slice(); // this is otherArray
yetAnotherArray.slice(); // this is yetAnotherArray

In your functions, there’s usually no need to re-assign this to anything else. In fact you generally want to stick to using this so people know you’re working from this magical reference which can be any object used to call the function.

Your example show this being assigned to input. While technically, there’s nothing wrong with that - both this and input now reference the same value, the tempArray, there’s no need to do it here. You can just use this instead.

Array.prototype.slice = function() {
  this[0] = "This is an awesome example!";
  return this;
}

I would say the input variable was used there for instructional purposes, to show that this is another kind of input, like arguments are. Just like arguments, it can change for every call.


#4

THIS (pun intended) made sense. Thank you.

It’s just so confusing because of having learnt C++ and C in school before(just the basics). Feel like I have to erase a lot of concepts I learned there to understand how JS works.

Like, in one of the examples in the book under Chapter 8, Closures, where a function is nested within a function with access to a variable that lies in the scope of the outer variable and returns the nested function, I discovered (at least it’s what I deduced, correct me if I’m wrong) that the inner nested function doesn’t get executed( sequentially), which isn’t at all how I expected that to work.


FUNCTION DEFINITION

function stopWatch () {
    var startTime = Date.now();
    function getDelay() {
        var elapsedTime = Date.now() - startTime;
        alert(elapsedTime);
    }
return getDelay;
}

var timer = stopWatch();

Here, the nested function getDelay() is returned by the outer function which is stored in timer, which now behaves like a function(what??). Why nest then?

Learning JS does a 180 to your brain. I’m currently at IFFE Chapter of the book. Progress was fast before but now I have to reread it a lot and reflect more than at the beginning of the book.

Thank you both @senocular and @kirupa for your reply again. This forum is amazing, and the instant feedback helps.
Cheers.


#5

Yup. Functions are first class objects. They can be stored in variables, passed around, and even given custom properties just like any other object. In fact, they’re like other objects in just about every other way except you also get a special behavior if you put () after their identifiers which invokes the code stored in the function’s body.

var obj = {};
function fun () {}

var temp;
temp = obj;
temp = fun; // OK

console.log(obj);
console.log(fun); // OK

obj.myValue = 1;
fun.myValue = 1; // OK

fun();
obj(); // NOT OK

What makes a function a closure is when it uses 1 or more [non-global] variables within its function body that aren’t a part of that function’s parameters or otherwise declared within the function itself. The getDelay function in your example does this with the startTime variable. startTime is declared in stopWatch, outside of getDelay, yet getDelay's function body reaches out and accesses it to use for itself. When it does this, it creates a reference to that variable and can access it whenever its called.

Closures then become similar to objects with special “properties” that exist as references to other variables. stopWatch creates a getDelay function that has a kind of startTime property associated with it, though its hidden from you the user because its not actually a property… though it could have been. Consider stopWatch written another way, since, after all, we just saw how functions can be given properties like objects:

function stopWatch () {
    function getDelay() {
        var elapsedTime = Date.now() - getDelay.startTime;
        alert(elapsedTime);
    }
    getDelay.startTime = Date.now();
    return getDelay;
}

This works the same way, only the variable we’re using to capture the startTime is assigned directly to the getDelay function. This also means its accessible in timer, the variable getDelay is assigned to when stopWatch() is called.

var timer = stopWatch();
alert(timer.startTime); // alerts startTime value set in stopWatch

The closure version doesn’t expose startTime as a property, though. Its simply an internal reference to the original variable from whatever scope it was originally defined. In stopWatch, its the local scope of the stopWatch() call. Normally local variables in a function call are destroyed when the function completes and returns, but since getDelay hangs on to startTime as a closure variable, it gets to live as long as getDelay (assigned to timer) does.

Ultimately, this becomes the purpose of the stopWatch function. Its a factory creating startTime variables and getDelay functions that access them. Each time its called, new versions of that variable and function are created, and though only the function is returned, the variable is still being used because of the closure reference that the function keeps to it.

Closures can get tricky, and it may take a while to get your head around them. The important bit is that closure variables are references not copies. Often people assume the value of a closure variable gets baked into a function, but thats not true. The value of the variable is accessed when the function is run, not created. This will often confuse people when creating functions in loops.

var funcs = [];
for (var i = 0; i < 3; i++) {
  function alertLoopValue () {
    alert(i);
  }
  funcs.push(alertLoopValue);
}

var lastFunc = funcs[2];
lastFunc(); // what's alerted?

At first glance, it looks like the obvious behavior here is that funcs[0] would alert 0, funcs[1] would alert 1, and funcs[2] would alert 2. But truth is, lastFunc, as well as all of the other functions in the funs array would alert 3. This is because, when you call them, them loop has already run through and incremented the i variable to 3, the first value that fails the loop condition of i < 3. And since closure variables are references, not copies, the value of i when the function is called gets used, not when it was created in the loop. There’s only one i variable, and every func function references that same variable and at this point, after the loop, that variable’s value is 3.

…It takes time. :slight_smile: