Javascript object's this scope, _this not fixing - javascript

Hello I am trying to create Tetris in JavaScript. I have map object with a variable called data. When I'm calling a function from the object, the 'this' is no longer the object but the local function I think. I have tried using declaring a variable _this = this in the objects constructor but doesn't help.
function Map(width, height){
var _this = this;
this.data = [];
for(var i = 0; i < width; i++){
var row = [];
for(var n = 0; n < height; n++){
row.push("0");
}
this.data.push(row);
}
}
Map.prototype.add = function(x, y, shape){
for(var i in shape){
for(var n in shape[i]){
_this.data[x+i][y+n] = shape[i][n];
}
}
}
var colMap = new Map(23,30);
var selectedShape = new FallingShape(0, 0, getShapeArray(randomShapeId(), 0));
colMap.add(selectedShape.x, selectedShape.y, selectedShape.shapeArray);
I'm trying to change the values of data but can't because of the scope, I've tried the '_this' trick but doesn't work. Can anyone help me understand?
Heres a link to a codepen page if you want to see the whole code. http://codepen.io/taylorlutjen/pen/OPGwoo?editors=001

Your _this local variable created in your constructor function is local to that function — it won't be available in the other function.
The good news is that you won't really need it - just use this in that .add() function.
Local variables in constructor functions are no different than local variables in any other function. They're not magic, and they definitely won't be available to other functions added to the constructor's prototype. The reason for creating a _this or that or self copy of the value of this is to be able to create things like callback functions that need a reference to the outer context object. None of your code (posted here) needs that.

Related

Why is the 'this' keyword needed in objects

From sololearn
function mathCalc (height, weight) {
this.height = height;
this.weight = weight;
// this.sampleCalc = ; (taken out)
}
Why do I need to do:
this.height = height;
this.weight = weight;
What is the reason behind it?
this is a keyword for the function's caller for function expressions and function declarations. For constructor functions (which I will demonstrate below) and object methods, this refers to the object itself. Here are examples of the types mentioned:
function myFunc() { return this; } //function declaration
const myVar = function() { return this; } //function expression
const obj = {a: 1, whatIsA: function() { return this.a } } //whatIsA is an object method
If you call either of the above functions from the global context (not inside another function), this is the Window object. The browser defaults this to the Window (which when you think about it, is the caller of the function since your browser ran the file).
myFunc(); //outputs "Window" obj
myVar(); //also outputs "Window" obj
For constructor functions instantiated with new, this is bound to the newly created object.
I think the best way to show why this is so useful is to give an example. Examine the following code:
function Dog(name) {
this.name = name;
this.bones = 0;
this.addBone = function(numOfBones) {
this.bones += numOfBones;
return this;
}
}
const clifford = new Dog('Clifford');
We have a constructor function (meaning we're going to be creating new objects from this function) called Dog.
Consider what happens when we create a new Dog named "Clifford". The new keyword creates a brand new object in memory for Clifford, which is an instance of the Dog constructor function. So since we created something that didn't exist before, this refers to the object itself. If we replaced this.name = name with let myName = name what would happen? We wouldn't be able to access myName because myName isn't part of our brand new instance of the Dog object.
Let's give Clifford a few bones.
clifford.addBone(1).addBone(2).addBone(3);
console.log(clifford.bones); //outputs 6
How is it possible we can chain methods as we did above? Because the method returns this!
When a function is called as a method of an object, its this is set to the object the method is called on.
So we're returning the object after adding a bone to Clifford's bones. This gives us back the object itself again.
Arrow functions behave slightly differently. this is inherited from the current lexical scope and not the caller.
height and weight are only parameters for the arguments passed into the function. If you're learning, it might help to use different names.
this refers to the function itself. When treated as an object/class, it will retain the values. Notice in the object output below that h and w are not retained, height and weight are. Also notice that one and two have different values, the same value that was passed into the function when they were initialized.
function mathCalc (h, w) {
this.height = h
this.weight = w
}
let one = new mathCalc(1,3)
let two = new mathCalc(2,4)
console.log('one:',one)
console.log('two:',two)
For a function that only gets called once, it makes complete sense to avoid this. However, for persistent state, this can be useful. Note that this only gets rebound when the new keyword is used.
function Worm() {
this.size = 1;
this.grow = function() {
++this.size;
}
}
const wormy = new Worm();
console.log(wormy.size);
wormy.grow();
console.log(wormy.size);
With ES6 Javascript, there is a much cleaner way to take advantage of this.
class Worm {
constructor() {
this.size = 1;
}
grow() {
++this.size
}
}
In short this is the owner object of the function. If you had two objects or elements that called upon a function - how would you place the appropriate value in the appropriate element that called it? Using this can eliminate the need for duplicate code etc.
Technically you don't HAVE to use it; but it has its uses.
You can read more here or here.
Here's a little click test snippet, where I can have one function for alerting this clicked div id rather than having to write one for each div;
var div = document.getElementsByTagName('div');
var i;
for (i = 0; i < div.length; ++i) {
div[i].onclick = function() {
alert(this.id);
}
}
<div id="test1">Click Test 1</div>
<div id="test2">Click Test 2</div>
<div id="test3">Click Test 3</div>
Mind you, this is easier in jQuery - but I didn't feel the need to include the CDN for this example. However, it would look something like this;
$('div').on('click', function() {
alert(this.id);
})
it's an easier way to write the name of an object, useful for larger programs that have many objects.

My for loop to create objects isnt working in .js with P5

I recently used P5 to make a Flappy bird like game and up until a day ago I used to define and call my objects for my game like this:
function setup(){
//**Define**
cloud1 = new Cloud(random(100, windowHeight - 500), random(0.7, 1.3));
cloud2 = new Cloud(random(100, windowHeight - 500), random(0.7, 1.3));
};
function draw(){
//**Draw Clouds**
cloud1.show();
cloud2.show();
};
This works fine, but when I tried to use a for loop in the following way:
function setup(){
//**Define**
for(var i = 0; i < 5; i++) {
cloud[i] = new Cloud(random(100, windowHeight - 500), random(0.7, 1.3));
}
}
function draw
//**Draw Clouds**
for(var i = 0; i < 5; i++) {
cloud[i].show();
}
}
The debugger says that my 'cloud' object isnt defined. I have used this kind of code in a very simmilar way before without any problems. Can anyone help me?
Sorry for my bad english.
First off, let's talk about why this works:
function setup(){
myVariable = 'hello';
}
function draw(){
console.log(myVariable);
}
Here, you're using the assignment operator to assign a value to a variable.
This works because when you hit the myVariable = 'hello'; line, JavaScript is going to look for a variable named myVariable in enlarging scopes (first in the setup() function, then in the global scope). When it doesn't find a variable with that name, it creates a new one in the global scope. More info on that here.
Now, let's talk about why this doesn't work:
function setup(){
myArray[0] = 'hello';
}
function draw(){
console.log(myArray[0]);
}
Here, you're using the index operator to index into an array named myArray. However, that variable hasn't been created yet! You could create the array first:
function setup(){
myArray = [];
myArray[0] = 'hello';
}
function draw(){
console.log(myArray[0]);
}
This will work for the same reason your first code worked. The myArray = [] line first looks for a variable named myArray, and then creates a new one when it can't find it.
However, all of the above is pretty hackish code, because it's relying on JavaScript to look through the various scopes. What if there's already a myVariable variable? You're now overwriting the value, which can lead to buggy behavior. At the very least, this is an unintended side effect, so it should be avoided.
Instead, what you want to do is declare the variable yourself, using the var keyword. Since you want to access the variable inside two functions, you'd want to do that outside of both functions, like this:
var myArray = [];
function setup(){
myArray[0] = 'hello';
}
function draw(){
console.log(myArray[0]);
}
Now this code creates a variable named myArray and sets it equal to an empty array. Then you can use the index operator on it to set an individual index, and you can access it in multiple functions. And even better, if there is a conflict with another variable, you'll get an error warning you about that.
var cloud=[];//must be global
function setup(){
for(var i = 0; i < 5; i++) {
cloud[i] = new Cloud(random(100, windowHeight - 500), random(0.7, 1.3));
}
}
function draw(){
for(var i = 0; i < cloud.length; i++) {//better like this
cloud[i].show();
}
}
If it has to be accessible by two functions you need to place the variable in a higher scope, and you may iterate over cloud.length elements, as hardcoded values can be overseen when changing.
Also, in such a case (without beeing in P5)my preferred setup would be like this:
function setup(num){
var cloud=[];
for(var i = 0; i < num; i++) {
cloud[i] = new Cloud(random(100, windowHeight - 500), random(0.7, 1.3));
}
cloud.show=function(){
this.forEach(el=>el.show());
};
return cloud;
}
So you could do:
clouds=setup(5);
clouds.show();
You need to create the empty array before you can assign to elements of it.
It's also best to declare your variables before using them.
var cloud;
function setup(){
//**Define**
cloud = [];
for(var i = 0; i < 5; i++) {
cloud[i] = new Cloud(random(100, windowHeight - 500), random(0.7, 1.3));
}
}
function draw
//**Draw Clouds**
for(var i = 0; i < 5; i++) {
cloud[i].show();
}
}

Access local variable of function inside callback

If I create a callback within a function, can I get that callback to access the local variables within that function?
Obj.prototype.outerFunc = function()
{
var x = 0;
var callback = this.innerFunc;
callback();
}
Obj.prototype.innerFunc = function()
{
x++;
}
x naturally is not within the scope of innerFunc and will produce an error if called by itself. But if I call it from outerFunc can I extend innerFunc's scope in order to access x?
Edit: Should've mentioned that I don't want to pass arguments into the function or make x and instance of Obj. I'm more looking to treat innerFunc as though it was declared locally in outerFunc. Similar to what can be done below:
Obj.prototype.outerFunc = function()
{
var x = 0;
var callback = function() {
x++;
}
callback(); // works
}
Yes: this is exactly what function parameters are for. They allow you to pass a value from one scope into another.
Obj.prototype.outerFunc = function()
{
var x = 0;
var callback = this.innerFunc;
x = callback(x);
}
Obj.prototype.innerFunc = function(x)
{
x++;
return x;
}
Note that the value is sent to the other function, not the variable. So you need to return the value and assign it in order to use it.
If you're using prototypes, just set an instance property:
// constructor
var Obj = function () {}
Obj.prototype.outerFunc = function()
{
this.x = 0;
var callback = this.innerFunc.bind(this);
callback();
}
Obj.prototype.innerFunc = function()
{
this.x++;
}
var instance = new Obj()
instance.outerFunc()
console.log(instance.x) // returns 1
Edit: But #lonesomeday's answer is a much better solution as it takes a more functional approach avoiding side effects :)
The preffered way of doing this is to assign x to the scope of the object then all functions can access it, via this.x
Obj.prototype.outerFunc = function()
{
this.x= 0; // set x to zero
this.innerFunc();
}
Obj.prototype.innerFunc = function(x)
{
this.x++;
return this.x;
}
This is a bit hard to solve without knowing why you don't want to pass a parameter; if you just want to have a specific function signature, maybe a higher-order function might help?
Obj.prototype.outerFunc = function()
{
var x = 0;
var callback = this.innerFunc(x);
callback();
}
Obj.prototype.innerFunc = function(x)
{
return function () { /* use x in here */ };
}
This way you have two functions one inside the other. The outer one takes the parameter, and the inner one can access the variable that is passed to the outer one.
This of course only gives you half of what you demonstrate in your example: You can access the local variable but not modify it.
You can never access any function's internal variables from outside the function under any circumstances, in an OOP context or otherwise.
The only sort-of-exception is that a function A defined inside a function B, and returned from that function B, continues to have access to the variables in function B--the basic notion of closure.
I have no idea why you don't want to use instance variables. That's what they're for--sharing data across methods. I have no idea why you don't want to pass values in or out--that's what parameters and return values are for.
can I extend innerFunc's scope in order to access x?
No, you can't, whatever that means. There is no such notion in JS.
The closest you can come to what you seem to maybe want to do is to define the variable in the constructor:
function Obj() {
var x = 0;
this.outerFunc = function() {
var callback = this.innerFunc;
callback();
};
this.innerFunc = function() {
x++;
}
}
However, this will not work as-is because this.innerFunc is missing its context. Therefore, you would need to write
var callback = () => this.innerFunc();
However, it's a mystery why you would want to do this instead of just writing this.innerFunc().

Bug in my Javascript Code: Scope Issue or Logic Issue?

My snake game is leaving a trail everywhere it goes, rather than moving properly: http://jaminweb.com/Snake.html
(Move it with the arrow keys)
I'm wondering whether this might be a problem of scope.
The relevant code is
var temp = this.body[0].clone();
// ....
this.body[0].translate(this.dx, this.dy);
for (var i = 1, j = this.body.length; i < j; ++i)
{
var lastBB = temp.getBBox();
var thisBB = this.body[i].getBBox();
temp = this.body[i].clone();
this.body[i].translate(lastBB.x-thisBB.x,lastBB.y-thisBB.y);
}
I'm wondering, dees
temp = this.body[i].clone();
inside the for loop create a new variable or does Javascript look outside to see if there's already one? I assumed the latter.
temp = this.body[i].clone(); creates a new object, thus you are creating new objects that don't get translated.
And as #MikeW pointed out in the comments, there is no for block scope in JavaScript; scoping is either global or limited to a function. So, temp in your code is the same variable both inside and outside of the for loop.
the this variable always points to the context that it is defined in.
function Constructor1
{
this.x = 1; // points to the objects instantiated by Constructor1
}
var a = new Constructor1;
a.x = 1; // `this` points to a
var b = new Constructor1;
b.x = 1; // `this` points to b
function func()
{
return this; // points to the calling function, returns itself
}
func() will return the function itself
Javascript uses functional scope as opposed to block scope.

Output of this javascript and the reason

function getCtr(){
var i = 0;
return function(){
console.log(++i);
}
}
var ctr = getCtr();
ctr();
ctr();
I've been using Javascript from last five years, but this question made me dumb in last interview. I tried everything to my knowledge but can't figure it out.
Can you please help me with the output and reason for it so that I can be better equipped for future interviews if I have one.
var ctr = getCtr();
This calls getCtr(), which initializes i to 0, and stores a reference to the function
function() {
console.log(++i)
}
in ctr. Because that function was created in the scope of getCtr(), the variable i is still accessible in the scope of the function stored in ctr.
The first call to
ctr()
executes console.log(++i) which has a preincrement on i, so it prints out 1. The second call executes the same code, with the same preincrement, and prints out 2.
DISCLAIMER: Not a javascript developer. Forgive me if I've made an error or used some unpreferred wording.
So the code you posted outputs 1 2. Yet the code:
function getCtr(){
var i = 0;
return function(){
console.log(++i);
}
}
getCtr()();
getCtr()();
outputs only 1 1!
The difference is that if you save a reference to getCtr() by using the var ctr = getCtr();, you create what is called a closure.
So the difference between calling getCtr()() and ctr() is that ctr has i defined in its scope, and that scope is saved thanks to var ctr = getCtr();. Because the reference is saved, the function inside of ctr is able to always act on the same variable.
run this:
var m=0;
var d=0;
alert(m++ +":"+ ++d);
and you get "0:1"
IF it were me asking in an interview, the difference in where the ++ is is what I would be after :)
http://jsfiddle.net/MarkSchultheiss/S5nJk/
Closures
The return statement in that function saves i. So when var i = 0; is only called var ctr = getCtr();. Then ctr becomes the returned function:
function () {
console.log(++i)
}
and the variable ctr has i in the scope of the outer function, getCtr() and the return function is in the scope of getCtr() as well.
okay, getCtr is a function that returns an other function.
It also contains a var called "i" which is set to 0.
"i" is also available in the scope of the returned function.
the preincrement of "i" before logging it to the console causes that it increases by 1 every time the returned function, which is stored in "ctr", is called.
When executed, function getCtr returns an inner anonymous function.
This function is now referenced by variable ctr
Because the anonymous function was created inside getCtr it will have access to getCtr private scope object, which contains variable 'i'. This is known as a closure.
var ctr = getCtr()
Every time the anonymous function is executed it pre-increments i, and writes in in the console.
ctr()
Lets break it down using terms you might know from classical inheritance based OOP languages:
// In javascript functions are first-class objects
// This function is being used like a class would be in Java
function getCtr(){
// You can think of this as a private variable of the getCtr "class"
var i = 0;
// Because it is returned, this is effectively a public method of getCtr
return function(){
// Which increments i and then prints it.
console.log(++i);
}
}
// This makes the variable ctrl an instance of getCtr.
var ctr = getCtr();
// This calls ctr's only public method.
ctr();
ctr();
So the output would be "1, 2".
What this question is meant to do is test if you understand Javascript's prototypal inheritance, ability to have anonymous functions, and closures.
A clarified version of that could that would do the same thing would be:
var myProtoype = function() {
var privateVariable = 0;
var privateMethod = function () {
privateVariable++;
console.log(privateVariable);
}
return {
publicMethod: privateMethod
};
}
var myInstance = new myPrototype();
myInstance.publicMethod();
myInstance.publicMethod();
That function is a Javascript Module. You can have a good reading about it on Javascript: the Good Parts, which is a great book and I highly recommend. A Module uses Javascript closures to create private variables and if assigned to a var the var will retain it's vars each time it's called instead of redefining the vars.
A module works like this
function moduleName(privateVar1){
var privateVar1;
var privateVar2;
return {
exposedFunction1: function (var1) {
// Do stuff... using private vars
return something;
},
exposedFunction2: function (var1, var2) {
// Do stuff...
return something;
}
}
}
var moduleInstance = moduleName(privateVar1);
moduleInstance.exposedFunction(var1);

Categories