Using "call" properly in Javascript to access object properties - javascript

I'm new to Javascript, and despite having read several threads and tutorials online, I can't correctly use "call" in this example to access the property of the object
I know the problem is that when "b ()" is called, "this" is the global object, and I have to use the call (or apply) method to make sure that when "b" is called this is set to the object itself, but I can't find the error.
I know that arrow functions exist, and that there may be other approaches, but I want to understand what is the matter with this using of call. Thank you.
The code is
class Letter {
constructor() {let a = "a";}
b() {alert (this.a);} //can't access a. Prints "undefined"
c() {this.b.call(this);}
}
let p = new Letter ();
p.c();

The a does not exist as a property of the object - it's a variable, an identifier visible within the constructor function, not an instance on an object.
There's no good way to gain access to a variable declared in another scope like that. For what you're trying to accomplish, define a as a property of the instance instead.
constructor() {
this.a = 'a';
}
You won't need .call at all - just do this.b().

Related

static variables within javascript functions and how it works under the hood

I'm having real trouble getting my head around some fundamental concepts in JavaScript so am hoping someone can give me a good explanation of what is happening under the hood in these examples.
CASE 1:
In this case I use the 'this' keyword in a constructor function:
function Counter() {
this.c = 0;
this.incC = function() {
return this.c++;
};
}
Obviously now I can instantiate the function and call the incC function to increment c and a record of c will be held in the created instance as the 'this' refers to the actual object being created. Here from my (limited) experience programming in C I imagine that when I do:
var counter = new Counter();
-the code is effectively allocating space for the object and then passing a pointer to that allocated memory into the constructor and that pointer is the 'this'.
But I have to wonder if I'm wrong because in case 2 things are a little different.
CASE 2:
In this function I can create a persistent variable using the 'this' keyword. However, I am not going to instantiate it, so it cannot be pointing to an object and it doesn't seem to be an attribute of counter (obviously the function itself is an object) as counter.c returns undefined.
function counter() {
this.c = this.c || 1;
return this.c++;
}
console.log(counter.c); // undefined
So what is happening under the hood in this example? Why and how is c not being lost when we exit the function and what is the 'this' pointing at in this example?
CASE 3:
Finally just to make things more interesting.
I came across this in a very old code base (I know there are more accurate ways to do inheritance but found this example interesting as to how it works exactly):
function CounterChild() {
Counter();
}
CounterChild.prototype = new Counter();
CounterChild.constructor = CounterChild;
var child = new CounterChild();
console.log(child.c); // 0
Here the this keyword relates to the object being instantiated, but how exactly does the call to the Counter() constructor get passed a reference to the object being created? I mean how does the interpreter know that this function should be passed a pointer at all as the new key word is not being used?
The most important thing to understand about this is that its value is determined by how the function called (expect for ES6 arrow functions, where this is lexically scoped, and functions that are bound via .bind).
Calling new Counter() is very different from calling Counter() and thus this refers to different values.
Overall I recommend to read MDN - this for more information about this.
Case 1
Yes
Case 2
Since the function is called "normally", i.e. as foo(), this refers to the global object, which is window in browsers. The code is equivalent to
function counter() {
window.c = window.c || 1;
return window.c++;
}
Case 3
how exactly does the call to the Counter() constructor get passed a reference to the object being created?
It doesn't. Calling Counter inside CounterChild() has no visible effect(*) here and you could simply remove it.
The c property comes from CounterChild.prototype.c, since you assigned a Counter instance to CounterChild.prototype. You can verify this by inspecting console.dir(child).
CounterChild.prototype is the prototype of all instances created through new CounterChild(). Any property that does not exist on an object itself is looked up in the object's prototype chain.
If you want this inside Counter to refer to the newly created object, you have to pass it explicitly:
function CounterChild() {
Counter.call(this);
}
*: That's actually not true. Just like in case 2, it does change the global variable c, but that is definitely not what you want.

"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.

confusion about the 'this' keyword in Javascript

I can claim that 'this' keyword is the most confusing part of Javascript for those who comes from languages like C#.
I have read a lot about this on the internet and on StackOverflow too. like here and here.
I know that 'this' keyword will be bound to the context. and in constructor function it will be bound to the object being created, and when there is no immediate context it will bound to global object (i.e window)
I know all that , however confusion is still not fully cleared; So the best way to understand is by testing codes.
So I decided to write small code and I was surprised by how much convoluted the this keyword.
here is the code i tested:
function sayHi(name){
var tt = name;
return {
ss: tt,
work: function(anotherName){
alert ("hiiiii " + anotherName);
}
};
}
//this method invocation has no effect at all right now
sayHi("John");
var hi2 = new sayHi("wallace");
hi2.work("May");
alert(hi2.ss);
as expected the alert window will show (Hiiiiii May ) then ( wallace). Notice now that the line sayHi("John"); has no effect at all.
and Now the confusion will start when I change one thing ONLY (change var tt => this.tt):
function sayHi(name){
//this is the ONLY change I did.
this.tt = name;
return {
ss: tt,
work: function(anotherName){
alert ("hiiiii " + anotherName);
}
};
}
// Now this line invocation will be problematic
sayHi("John");
var hi2 = new sayHi("wallace");
hi2.work("May");
alert(hi2.ss);
the result surprised me when the alert mthod gave ( Hiiiiiii May ) and then (John) not (wallace);
so I had the idea to comment the line sayHi("John"); but that resulted in the whole code being no-functional and not working.
the demo is here
I know this might be newbee question. But it is really confusing here and I did try to read many articles and SO questions but i m missing this point.
Why does the line sayHi("John"); setting the hi2.ss to John?? and why does it break the code when we delete it ; although we invoke the sayHi method by using the new keyword afterward ??
Because you assign the parameter "name" to a property of the object referenced by this (which in this case will be window), your subsequent reference to "tt" in that object literal will be to the "tt" property of the global object, since that's the next enclosing scope.
Your first call to "sayHi" is made without the new operator, so in that call this will refer to the global object (window). The first line in the second version
this.tt = name;
therefore will set window.tt to "John".
The next call is made with the new operator. Because of that, this in the function refers to the newly-instantiated object. The line
this.tt = name;
will therefore really have no net effect on anything, because the function returns a different object in all cases. The last line of your test:
alert(hi2.ss);
says "John" because that's what's in window.tt. Why does that matter? Because "sayHi" returns an object with a property ("ss") set from the value of the symbol "tt". The only "tt" in scope will be window.tt, which was set back in the first call to the function.
When you first invoke sayHi("John");, this will point to the global object window. That means this.tt = name actually creates a global tt variable.
Then when you invoke new sayHi("wallace");, this correctly points to a new instance of sayHi, but you are returning another object instead of letting new naturally return the instance.
If you carefully look at your object literal, you define ss like ss: tt,. Since you aren't using this.tt and there is no tt symbol found in the constructor's scope, the value will then be resolved as a global variable (which was previously set to John).
When invoking a constructor function, if no return statement exists in the function then this is implicitly returned otherwise the return value is returned and this is simply ignored.
In your second example you are saving the name argument as this.tt but returning a different object. That's why things aren't working. Basically use this or return a custom object, but don't do both.

Do I always have to apply the "this" ( or "that" ) scope to all object properties in JavaScript?

I'm trying to write an application in JavaScript, which I've been using for bits of scripting in web pages for years, and I find my understanding of scope and object orientation is coming up somewhat short. My background is mostly in object oriented languages like C# and Ruby so JavaScript's weird pseudo object-oriented functional approach is confusing me no end.
What I'm having trouble with is this and why I seem to always need it in every reference to anything in my class. It just seems to result in an inordinate amount of typing in order to write much that is useful in JS and I can't help but feel I must be doing it wrong somehow:
function MyClass()
{
var a=1;
this.b = 2;
this.internalMethod= function()
{
console.log("a is: "+a); // returns "a is: 1"
// console.log("b is: "+b); - this fails because b is undefined
console.log("this.a is: "+this.a); // returns "this.a is: undefined" but doesn't crash.
console.log("this.b is: "+this.b); // returns "this.b is: 2"
}
}
MyClass.prototype.externalMethod = function()
{
// console.log("a is: "+a); - fails
// console.log("b is: "+b); - fails
console.log("this.a is: "+this.a); // "this.a is: undefined"
console.log("this.b is: "+this.b); // "this.b is: 2"
}
var m = new MyClass();
m.internalMethod();
m.externalMethod();
What I am understanding from this is that if I am adding a new public method through the class.prototype approach, I only have access to properties that are defined with this.
If I create an internal method in the class definition function I have access to any var values in the class itself and I can access this.property as long as I include the this.
Is this correct? Do I always have to include an explicit object reference to access properties in any functions that use the prototype method? If so, should I be declaring all my functions within the parent class function rather than using the class.prototype pattern for adding them?
In essence I am looking for a standard approach to managing variable scope when writing object oriented Javascript. Most of the articles I can find on this topic are either basic introductions to object orientation or seem to gloss over this area. A lot of my classes are fairly data intensive and having to make calls in the form this.myMethod( this.firstArray, this.secondArray, this.thirdArray, this.fourthArray ) seems like a long cut and impedes the readability of code.
(I am aware of the var that=this trick for avoiding caller scope problems but I didn't want to mess up my examples with it as as far as I know it's not really pertinent to my question.)
function MyClass()
{
var a=1;
this.b = 2;
this.internalMethod= function()
{
console.log("a is: "+a); // returns "a is: 1"
// console.log("b is: "+b); - this fails because b is undefined
console.log("this.a is: "+this.a); // returns "this.a is: undefined" but doesn't crash.
console.log("this.b is: "+this.b); // returns "this.b is: 2"
}
}
In that code, the first console.log will return the right value, because you declared the variable a and then declared the function, which grabs it's environment and saves it all into something called closure (this explanation might be a bit off), so what happens here, is that when you call internalMethod, that function in it's environment also has the definition of a. Which might be confusing, because when you do your second console.log your see "undefined", which is because the a variable is not an attribute of this, but rather just a global variable to the scope of your internalMethod.
MyClass.prototype.externalMethod = function()
{
// console.log("a is: "+a); - fails
// console.log("b is: "+b); - fails
console.log("this.a is: "+this.a); // "this.a is: undefined"
console.log("this.b is: "+this.b); // "this.b is: 2"
}
In that code, a is not defined, becuase it didn't exist when you declared your method, but this.b does, because is part of the attributes of MyClass, which is what you're working on.
So, to summarize, you'll want to use the this keyword when adding or using internal attributes to your "class" (which you should not call class, since that doesn't exists here). It might be a pain, but it's the only way to reference internal attributes of your objects from within it's methods.
Additionally, you might find these two articles interesting to read, since they explain a bit about OOP techniques for JS and some common mistakes:
http://www.commented-out.com/2012/06/12/javascript-oop-for-the-uninitiaded/
http://www.commented-out.com/2012/05/28/javascript-youre-doing-it-wrong/
Let me know if you have more questions.
What I am understanding from this is that if I am adding a new public method through the class.prototype approach, I only have access to properties that are defined with this.
If I create an internal method in the class definition function I have access to any var values in the class itself and I can access this.property as long as I include the this.
There are no such things as "internal" and "external" properties, only "own" and "inherited" properties. In your example, internalMethod is directly assigned to the new object, while externalMethod is inherited from the prototype. They are not different or special in any way. Any two functions that are defined in different scopes are always different.
internalMethod has access to the local variables in the constructor because it is a closure.
Do I always have to include an explicit object reference to access properties in any functions that use the prototype method?
It's important to understand that there is no implicit connection between functions and the objects "they are assigned" to. Functions are independent entities.
The connection is only determined at runtime, by setting this accordingly. So yes, you will need this, for every function, not only those assigned to the prototype. Learn more about this.
If so, should I be declaring all my functions within the parent class function rather than using the class.prototype pattern for adding them?
This is extensively discussed here:
Declaring javascript object method in constructor function vs. in prototype
Use of 'prototype' vs. 'this' in JavaScript?
In essence I am looking for a standard approach to managing variable scope when writing object oriented Javascript.
My subjective advice:
Keep it simple. Don't try to simulate private variables/methods through local variables and closures. Initialize and assign instance-specific data in the constructor, and assign anything that should be shared between instances (such as methods) to the prototype. Use a naming convention, such as this.privateProperty_ to indicate properties that should be accessed by external code.
A lot of my classes are fairly data intensive and having to make calls in the form this.myMethod( this.firstArray, this.secondArray, this.thirdArray, this.fourthArray ) seems like a long cut and impedes the readability of code.
In this example, this inside myMethod will refer to the object itself, so you can access this.firstArray, this.secondArray, etc, just in like that inside the function. You don
t have to pass them.
JavaScript doesn't look up variables in an object, because it's not a classical inheritance language. It's more based on Scheme, with its lexical scope.
Your examples show 2 things:
this refers to the object being instantiated
a is just a variable
In the internalMethod, you're still in the constructor function. So you have access to the variables defined in the constructor (function scope and lexical scope). However, once you get out of the constructor, a is not reachable anymore.
this.b means that on the instantiated object, you attach the property b. It's basically the equivalent of this:
function Foo() {}
var foo = {
b: ''
};
foo.constructor.prototype = Foo.prototype;
Basically. Instantiating with new does a little bit more.
So if you want to access the instantiated object, you have to use this. If you just want to use the power of lexical scope, you can also play with simple variables and closures.
For example, this constructor will instantiate a new object every time it's called, and there is no this:
function Foo() {
var a = 1;
var b = 2;
return {
internalMethod: function() {
return a;
},
incB: function() {
return ++b;
}
};
}
var foo = Foo();
foo.internalMethod(); // 1
foo.incB(); // 3
foo.incB(); // 4
var bar = new Foo();
bar.incB(); // 3
This pattern is called the "module pattern".
If you find limiting the use of an object, you can return an object by using a immediately-executed function (and thus having another scope to play with):
function Foo() {
var a = 1;
var b = 2;
return function() {
var c = 3;
return {
a: a,
c: c
};
}();
}
I seem to always need it in every reference to anything in my class. It just seems to result in an inordinate amount of typing in order to write much that is useful in JS
You're not doing it wrong. In my comment I referenced this answer where I try to explain every stage of writing a constructor, after reading it you'll understand why it's not wrong to use this, however, JavaScript does provide another statement, with that you could use to reduce how much you need to type after a property is initialised.
function MyConstructor() {
this.a = 1; // initialise properties with `this`
this.b = 2;
this.c = 3;
this.d = 4;
}
MyConstructor.prototype = {};
MyConstructor.prototype.foobar = function() {
var c = 5, e = null;
with (this) { // `with` now means you can do `a` instead of `this.a`
var d = 6;
console.log(a, b, c, d, e);
a = 0 - a; // in `this`, property gets set to property
b = -2; // in `this`
c = -c; // in `this`, var'd outside `with`, property gets set to property
d = -d; // in `this`, var'd inside `with`, property gets set to var
e = 100; // not in `this`, var'd, var gets set (not var'd => global set)
}
};
x = new MyConstructor(); // new instance
console.log(x.a, x.b, x.c, x.d, x.e);
// 1 2 3 4 undefined -- undefined as no property `e`
x.foobar();
// 1 2 3 6 null -- 6 from var, null from `var e = null`
console.log(x.a, x.b, x.c, x.d, x.e);
// -1 -2 -3 -6 undefined -- undefined as still no property `e`
I suggest reading about the Javascript module pattern to learn about public / local attributes and scope.
var declares a variable that will be accessible in the current function and the inner ones.
Any method / attribute attached to an object is said "public" as it can be accessed from anywhere.
Local variables, 'trapped' in closures, are used to emulate private members.
Attaching public methods to the prototype is the best memory-efficient approach to reuse those methods on different instances. You could use closures as well in those prototype methods.
One thing to note: as closures emulate 'private' variables but not 'protected' ones, it makes inheritance quite tricky when you need it.

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