What is an instance variable in JavaScript? - javascript

In a React tutorial video, the instructor said you need to use this.props rather than just props in a React class component because in that case, it's an instance variable. I'm not totally sure what an instance variable is in that context.
I found a lot of questions explaining what an instance variable is in the context of Java and other languages besides JavaScript--in one question (tagged objective-c), someone answered "In object-oriented programming with classes, an instance variable is a variable defined in a class (i.e. a member variable), for which each object of the class has a separate copy. They live in memory for the life of the class."
However, I know ES6 classes are just objects and are syntactical sugar for prototype-based inheritance --would that answer hold true in the case of JS classes?

To understand this thing, you need to know about function expression, lexical environment, prototype inheritance.
'this' keyword refers to the object it belongs to.
let say we have a class like this,
class Hello{
constructor(name){
this.name = name
}
hello(){
console.log(this.name);
}
}
now let's make a new object with the help of this class.
var person = new Hello('Alex')
Now I can do something like this,
person.hello();
This line will return 'Alex';
Now let's console.log(person);
console.log(person)
person ==> {
name : 'Alex'
<prototype> {
constructor: function Hello()
}
}
You will notice that Hello function is not at the top level of the person object. It is at the first prototype level of that object. Everything inside of this prototype will refer to the class or Factory function or
Constructor function that helps to define that person object. In this case, it refers to Hello class.
var person is defined on the global level. so when you call to person.hello() it will check at the top level of that object. If it is not in there, then it will go to the outside environment and try to find out what is this hello() thing. The outer environment of this person object is the global level. hello() function is not at the global level. When javaScript did not find the hello() in the outer environment then it will throw an error that saying hello() is undefined.
When we use 'this' keyword, it will say check on prototypes too. go through all the prototypes until you meet that thing. If it is not in there, then go outer environment and check if it is there.
'this' keyword will refer anything, to the object it belongs to. Also, remember everything in javaScript is an object expect primitive data

An instance variable is just a property of an object, as Felix Kling said.
You can't use props because that's referencing a global or local variable called props. What you want to access is the current value of props for the current component, stored in this.props.
See a jsfiddle: https://jsfiddle.net/vd5ymhcz/1/

An object is an instance of the class that it is created from. And an instance variable is any property defined in the class for that object (typically inside constructor).
Every instance variable is accessible using 'this.' prefix inside any method of the class.

Related

"super" keyword cannot access parent property in javascript

class Base{
constructor(val){
this.val = val;
}
basep = 'default1';
basef(){
return 2;
}
}
class Test1 extends Base{
constructor(val,name){
super(val);
this.name=name;
}
getp(){
console.log(this.name,this.val);
console.log(this.basep); //(in case of proerty) result: 'default1'. if "this" is changed to "super" ===> result: undefined
console.log(super.basef()); //(in case of methods) this and super both work.
}
}
test= new Test1(1,3);
test.getp();
In java 'this' and 'super' worked both fine to get parents property but it seems in javascript only this works.
why is the difference?
In Java, attribute names are put in a scope, and you can have two different attributes with the same name if they were created by different classes. This is not how it works in JavaScript with prototypical inheritance at all, though.
In JavaScript, data properties (that are created by assignment) are owned by the object itself. The parent constructor created the .basep property directly on the child instance. this.hasOwnProperty('basep') will be true.
The super keyword is used to access properties on the parent's .prototype object, regardless of what the current this value is, but still allows calling them on the this object. The basef method lives as a property on Base.prototype, basep does not.

In a class constructor why is "this required"? why cant I use local variables?

I know that local variables dosent work when testing it, but I dont understand the concept. Why does "this" work and local variables does not? a clarification would be great on why I must use this and avoid local variables!
code:
function Person(job, married) {
var employ = job;
var status = married;
}
var ray = new Person("student", true);
console.log(ray);
You can use local variables in your constructor, but they don't automatically become instance variables of your object. Instead, the way you are using them, they are just temporal local variables, like local variables inside any function definition.
When you do this:
function Person(job, married) {
var employ = job;
var status = married;
}
var ray = new Person("student", true);
Here's what is happening:
You define a function named Person.
In that function, you define two local variables named employ and status.
Those are normal local variables within a function. They are only visible to code within that function. These may be useful for some things, but they are not available to any code outside that function. They are not available to prototyped methods of your object, they are not available to other code outside that function. In fact, without some sort of reference that creates a closure, they have a limited lifetime and are gone and garbage collected as soon as the Person function finishes executing.
So, if you intended to create the C++ equivalent of member variables of your object, this did not accomplish that. The variables are used only for the duration of the Person() function and are then disposed of and have no lasting presence.
Then, when you execute var ray = new Person("student", true);, the following things happen.
The new causes the system to create a new object, set the value of this to point to that new object and then call the Person constructor with your two arguments.
Your code then creates two local variables which you assign the two arguments to.
The Person() function then finishes executing and the two local variables are disposed of because the scope in which they were defined is done and is garbage collected.
You then assign the newly created object to the variable ray. It is indeed a new object, but it has no custom instance data because nothing was stored in a lasting way.
If you then do console.log(ray), you're just going to see an empty object with no instance data other than what the default Object instance has. Your custom data was not stored anywhere lasting so it's gone now.
If you intend for those two arguments to be saved somewhere lasting as instance data of the object, you have a couple choices. The more traditional choice is to make them publicly accessible properties of the object. You would do that like this:
function Person(job, married) {
this.employ = job;
this.status = married;
}
Since this points to the newly created object, this code assigns the job and married arguments to properties of the newly created object. These properties can be accessed either by other methods on the object or by any code outside of the constructor like this:
var ray = new Person("student", true);
console.log(ray.employ); // "student"
console.log(ray.status); // true
These properties are publicly accessible.
There are some interesting things you can do with those local variables that can allow them to persist and be used after the object is created. To do that, you have to create a closure. I think of a closure as a function scope that would normally be discarded when the function finishes executing, but because of circumstances, there are still live references within the function scope so the garbage collector does not throw away the function scope when the function finishes executing like it would in a purely stack based language like C++. Instead, it persists and can be accessed by code after the object has been created. Here's an example:
function Person(job, married) {
var employ = job;
var status = married;
this.getEmploy = function() {
return employ;
}
this.getStatus = function() {
return status;
}
}
var ray = new Person("student", true);
console.log(ray.getEmploy()); // "student"
console.log(ray.getStatus()); // true
Here's the assignment of functions within the constructor has created a closure. The private local variables employ and status are still private to within the scope of the Person function. But, because the getEmploy and getStatus properties are now publicly exposed and can be called at some time in the future and those functions reference the employ and status variables, the garbage collector realizes that it can't garbage collect the employ and status variables so they persist for the lifetime of this newly created Person object.
Using terms familiar to other object oriented languages like C++, the employ and status local variables are giving you some of the features of private instance variables. Some people call this a hack to fill the void of a feature that Javascript does not offer quite so directly. But, I don't see it as a hack. The language offers closures as an enormously useful feature that can be used in so many ways and this is just one way of using a closure to create a benefit, the benefit of private instance data.
Only the publicly assigned properties getEmploy and getStatus can be accessed by the outside world, but by calling them, we can access the private variables employ and status. If we do console.log(ray) in this new model, we still won't see employ and status there because as far as the console is concerned, they still aren't properties of the ray object. But, because of closures, they are uniquely accessible by the methods on the ray object.
Further, because a new closure is created each time we call the Person constructor, these employ and status variables are uniquely associated with each new instance of the Person object. They behave and work like private members of the object.
For more examples of this type of structure and some more explanation, see this classic discussion: http://javascript.crockford.com/private.html
Why does "this" work and local variables does not?
Unless some sort of lasting closure is created, local variables are temporal. They last only as long as the containing function is executing and they are then garbage collected. Just because they are declared inside a function that you are using as a constructor does not make them special. They are just local variables and have no magic powers beyond just being local variables.
In a class constructor why is “this required”?
a clarification would be great on why I must use this and avoid local
variables!
If you want to assign properties to your object, it is this that points to your object in the constructor so the only way to assign to a property of your object is to reference the object as this.someProperty = xxxx. That's just how the language works. All property references in Javascript require an object as the first part of the access. And, in a constructor, the reference for the newly created object is this. That's how the language was designed.
Those coming from some other object oriented languages might thing you can declare an instance variable of a class and then just use that name all by itself and the interpreter will somehow just know that it's an instance variable name, not a variable name. That might be true in some other languages. That is not true in Javascript. All property references, whether in the constructor, in some method or accessed from the outside as a property on an object must all use an object as the base of the reference. And, inside the constructor and inside a method, that base is the value of this. So, this.someProperty is how you reference that property on the current instance.
Think of it like this:
A class is basically an object, right? Well, when you declare a new instance of Person, you're saying "let's create a new object with properties x, y, and z." Using "this" allows you to access the properties for that instance later, while local variables aren't treated as properties for your object.
When a function is called as a constructor (using the new keyword), a new object is created (the instance object), prototyped on the object value of the function's prototype property, and the constructor called with its this value set to the new instance object just created.
Constructor code can set properties and methods on this (the instance object), which is the return value of the constructor call (... unless the constructor explicitly returns some other object).
If variables defined within the constructor are accessed by nested functions which persist after the contructor returns, they will not be garbage collected because they can still be accessed. If they are not accessible after the constructor returns they are essentially discarded and become available for garbage collection.
Object creation is fundamental to JavaScript behavior: Try looking up and reading about the use of constructor functions.
More about retention of variables in the scope of nested functions after an outer function exits can be found by searching for "closures in JavaScript".

"this" as scope limiter?

I'm trying to understand "this" and everything I've looked at talks about context. What this has led me to is the idea that "this" is a scope limiter. It makes sure your variables are referenced using the proper scope, mostly by keeping variables "local" -ish in scope, and keeping them from reaching too far out from where the running code is.
My question is: is that correct? I tried to do searches using the concept I'm trying to get across, but those came up with totally bad results. There is a lot of nuance with "this", and from the reading I've done, I feel like this is a better explanation than what I've seen, but I want to make sure I'm correct in that thinking.
this and variable scope are separate concepts. Variable scope refers to which variables can be accessed from where within your application. Just because you wrote var foo somewhere doesn't mean that you can access it from everywhere throughout your codebase. In Javascript each function introduces a new scope, and scopes nest in a way that inner functions have access to the scope of outer functions, but not vice versa.
this on the other hand is simply a "magic" reference to the "current" object. Maybe it's helpful to explain this idea in the context of other, classical languages first:
class Foo {
protected $bar;
public function baz() {
echo $this->bar;
}
}
In PHP the magic keyword $this refers to the current object instance. Each time you call new Foo, a new instance of this class is created. Every time you call $foo->baz(), the same function is executed, though with $this set to the appropriate object instance so each object instance can access its own data.
In Python this is actually a lot more explicit:
class Foo:
def baz(self):
print self.bar
Python does not have a magic keyword to refer to the current object instance. Instead, every method call on an object gets the current object passed explicitly as its first argument. This is typically named self. If Python seems too alien to you, the above in PHP syntax would be:
class Foo {
public function baz($this) {
echo $this->bar;
}
}
Technically the functions in those classes do not really "belong" to any "class". They're just functions. You just need some way for those functions to be able to refer to a polymorphic object in order for them to be instance methods. Take for example:
function baz($obj) {
echo $obj->baz;
}
That's essentially exactly the same as what the class method does above, with the difference being that $obj is explicitly injected instead of $this being magically "there".
Javascript has the same thing, except that this is available in every function (not just "class" functions) and that the object this points to can be freely changed at runtime. this is simply a magic keyword that points to an object, period.
function Foo() {
this.bar = null;
this.baz = function () {
console.log(this.bar);
}
}
When calling regular functions on objects like foo.baz(), this typically refers to foo inside of baz(); though it really doesn't have to:
foo.baz.apply(someOtherObj);
This takes the function foo.baz and calls it while setting the this keyword inside baz to someOtherObj. It freely re-associates the function with another object instance, if you will. But only because the only thing that "bound" the function to the object in the first place was the this keyword anyway. The function will still simply do console.log(this.bar), whatever this.bar refers to.
A more complete example:
function Foo() {
this.bar = 'baz';
}
Foo.prototype.speak = function () {
alert(this.bar);
};
var o = new Foo();
o.speak(); // alerts 'baz'
alert(o.bar); // also alerts 'baz'
var o2 = { bar : 42 };
o.speak.apply(o2); // alerts 42
As you can see, this doesn't limit the scope of anything. What's happening here?
The Foo constructor is called with new Foo(). new simply creates a new object and executes Foo() with this set to this new object. Basically:
var tmp = {}; // tmp does not *actually* exist,
// that's more or less what `new` does behind the scenes
Foo.apply(tmp);
The Foo constructor assigns the bar property of that new object.
tmp.bar = 'baz';
The new object is assigned to o.
var o = tmp;
o.speak() is a function bound to that object through its prototype. Calling it as o.speak(), this inside speak() refers to the o object. Because that object has a property bar, this works.
Notice that it's also possible to do alert(o.bar). The .bar property was set on this originally, then this became o. So o has the property .bar, which is a regular property of the object. It's not scope limited or anything.
Next, we simply create another object o2, which also happens to have a bar property. Then we call o.speak, but we explicitly override the choice of what this refers to using apply. We simply do a switcheroo on what object the this keyword refers to. Thereby the speak function alerts the bar property of the o2 object.
As you see (hopefully, I know this can be brain bending at first), this is nothing more and nothing less than a reference to an object. That's all. It doesn't limit at all the scope of anything. functions limit scopes, this is just an arbitrary object. Anything you set on this is not limited in scope; on the contrary, it's always publicly accessible from anywhere you have access to the object.
It's incredible how trivial it all is once you manage to wrap your head around it. this refers to an object, it is simply Javascript's magic keyword to refer to an object. There are certain trivial rules which object it refers to at any given time, but all those can be bend and broken and reassigned. An object is simply a thing with properties. The properties can be functions. Only functions limit variable scope. That's pretty much all there is to it. Don't try to interpret anything else into this.

Why do Javascript "class" implementations overwrite the class name with an identically-named function declaration?

I'm studying Coffeescript's output to try and get a solid understanding of what's happening behind-the-scenes. When I declare a new class Person, a variable named Person is created containing an IIFE.
var Person;
Person = (function() {
function Person() {
this.doThing();
}
Person.prototype.doThing = function() {};
return Person;
})();
What's throwing me here, is that the IIFE itself contains a named function declaration called Person. Does this overwrite the original Person variable, or does Javascript consider this a new scope? When doThing is added to Person's prototype, which object is that specifically referring to?
Perhaps my question betrays a deeper confusion :)
The IIFE, being a function, creates a new scope so that all of the 'class' logic is nicely hidden away. The Person inside the IIFE is returned and assigned to the Person outside of it, but if the IIFE returned something else, then that is what the outer Person would be.
doThing is assigned to the prototype Person inside, but again since Person is returned, it is the same function object references inside the IIFE.

referring to prototype method within class variable

I'm having trouble with a JS prototype object I'm working on. What I'm trying to do is define a class-level variable as an object literal, then refer back to one of the class's prototype methods to set a property of the class-level variable, but I'm not getting anywhere. Here's what I am trying to do, in a simplified example:
var foo = function(args)
{
this.name = 'bar';
}
foo.stuff = { barbaz: this.foobarbaz(2) };
foo.prototype.foobarbaz(int)
{
return int;
}
alert(foo.stuff.barbaz); // should alert 2, but I'm missing something
I'm wondering if I'm just misunderstanding the scope of 'this' in this instance, or if this.foobarbaz() is undefined when I assign it to foo.stuff.barbaz.
Is it possible to refer to an object's prototype methods from within a class-level variable like this?
Here is what you need to know:
You should define your method on the prototype like foo.prototype.foobarbaz = function(int) {...}. Your current syntax is not valid.
You're trying to use the method before you define it. If you're expecting function hoisting to work here, that only applies to function declarations, not assignments. Move the assignment of foobarbaz above the first time you use it.
In this function you've provided, this is not foo. Each function has its own value of this (called the function's "context"), set each time the function is invoked. You can see the rules for how a function's context is set in several answers to Understanding Javascript scope with "var that = this".
Instead, here, you'll need to use foo.foobarbaz(2) instead of this.foobarbaz(2), because this is probably window (assuming you call this code not as the method of an object and not in JavaScript's strict mode).

Categories

Resources