Accessing the parent object of a function in Javascript [duplicate] - javascript

This question already has answers here:
JavaScript - Owner of "this"
(6 answers)
Closed 8 years ago.
I have this function right here which takes the parts of my object and illuminates them successively with a delay (it switches the opacity of an element to 1 and then switches the previous element opacity to 0 to illuminate them successively).
The problem is that I cannot use the this keyword to access the parent objects parts in the illuminateInternal function.
This hinders any possible reuse of my object since I will have maleBackNoZoom and maleBackFullZoom objects.
I don't want to change the variable names of the illuminateInternal function when I re-use my object so I would like to use something like the this keyword in the illuminateInternal function as well.
maleBackNoZoom = {
parts:{
armsRight: findItemById("29") ,
armsLeft: findItemById("28"),
legsRight: findItemById("21"),
legsLeft: findItemById("22"),
back: findItemById("24"),
buttocks: findItemById("23"),
neck: findItemById("26"),
head: findItemById("27")
},
illuminate: function() {
var propertiesToIlluminate = [], prop, illuminateInternal, i = 0, delay = 200, intervalId;
for (prop in this.parts) {
propertiesToIlluminate.push(prop);
}
illuminateInternal = function () {
var property = propertiesToIlluminate[i];
var previousProperty = propertiesToIlluminate[i-1];
maleBackNoZoom.parts[property].opacity = 1;
console.log(previousProperty);
if (typeof previousProperty !== 'undefined'){
maleBackNoZoom.parts[previousProperty].opacity = 0;
}
paper.view.update();
i++;
if (i === propertiesToIlluminate.length) {
maleBackNoZoom.parts[property].opacity = 0;
clearInterval(intervalId);
setInterval(function(){paper.view.update()},delay);
}
};
intervalId = setInterval(illuminateInternal, delay);
}
}

You can define local variable inside illuminate method which will store reference to its object. And then you can use it as alias of this.
var self = this;
illuminateInternal = function () {
..
self.parts[property].opacity = 1;
}

Related

Can I add/declare properties to a function in JavaScript?

I'm developing a RPG using HTML, CSS and JavaScript with jQuery as a personal project. Right now I'm doing the HUD where the player will have buttons to display information such as the Character Information, inventory, etc. Each of these buttons on will create a div where the info required will be displayed, if clicked again and the div is open it will delete it (or close it).
As far as I understand, functions in JS are treated as objects and thus properties can be added, I want to add a boolean property to the function that creates the div as a flag to check if the window is open or closed so I don't have to declare a global variable as flag to each button.
How do I declare those properties in a function?
Example:
let windowCharInfo = () => {
this.opened = false;
this.windowDisplay = function() {
$('<div>', {
class: 'HUDWindow',
id: 'charInfoWindow'
}).appendTo('#charInfo'); // Here's the window that will be created
// Some other code to add elements to that window will be here
}
}
The let windowCharInfo() is already an object or do I have to store it in a variable using 'new' keyword?
Also, windowCharInfo() will be called when the user clicks '#charInfo' (using onclick: 'windowCharInfo()')
Here is a Simple Constructor:
function Player(type) {
this.type = type;
this.weapons = []; // public
var thaco; // private
this.setTHACO = function(thaco) {
this.thaco = thaco;
return this;
}
this.getTHACO = function() {
return this.thaco;
}
this.addWeapon = function(weapon) {
this.weapons.push(weapon);
return this;
}
}
var player1 = new Player('elf'); // now it's an Object
player1.addWeapon('sword').addWeapon('axe').setTHACO('18');
console.log(player1.type);
var weapons1 = player1.weapons;
for (var i = 0, l = weapons1.length; i < l; i++) {
console.log(weapons1[i]);
}
console.log(player1.getTHACO());

Javascript Class, access property callback [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
I have the following javascript class similar to this:
class ModalFormButton {
constructor() {
this.contactForm = new ContactForm();
let utils = new Utils();
this.$signupModal = $(utils.getModalTmpl());
}
loadContactForm() {
this.$signupModal.modal();
this.contactForm.load();
}
contactBtnHandler(e) {
e.preventDefault();
let utils = new Utils();
var $t = $(this),
$modalTitle = $t.data('modal-title'),
$modalFormId = $t.data('modal-form-id');
$('body').append(this.$signupModal);
this.$signupModal.find('.modal-title').html($modalTitle);
this.$signupModal.find('.modal-body').load($t.attr('href') + ' #' + $modalFormId,this.loadContactForm);
};
registerHandlers() {
$('.modal-form-btn').click(this.contactBtnHandler);
};
load() {
this.registerHandlers();
};
}
My problem is that when contactBtnHandler is called I don't have access to class properties because the context belongs to modal-form-btn.
I know I can solve this using an arrow function, but I am wondering about if its possible to separate in a function the logic in the callback (here is a short example but I have longer functions) in a way similar to the one I am using.
Thanks
You can try binding "this" to your class in your callback handler
registerHandlers() {
$('.modal-form-btn').click(this.contactBtnHandler.bind(this) );
};
One could do:
getHandler (){
return e => {
//this is ModalFormButton
};
}
And then:
$('.modal-form-btn').click(this.getHandler());

Javascript ES6 calling a method inside another method within the same class shows an error the class i am calling is undefined [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
I am using Javascript ES6 classes. I have created a Player class as below:
class Player {
constructor() {
.....
.....
}
changeShipDirection(shipName, direction) {
let redraw = false;
this.ships.filter(function(ship) {
if (ship.name === shipName) {
ship.direction = direction;
if (ship.location.length > 0) {
redraw = true;
let coordinates = this.getCoordinatesOfShip(ship.name);
}
}
});
return redraw
}
getCoordinatesOfShip(shipName) {
let coordinates = [];
this.ships.filter(function(ship) {
if (ship.name === shipName) {
coordinates = ship.location;
}
});
return coordinates;
}
}
I get the following error:
Cannot read property 'getCoordinatesOfShip' of undefined
I have cases where I use the same technique i.e. calling a method within the class and it works.
That's because this inside that function you passed to filter is not bound to the class. There are multiple ways to fix it.
One is to use arrow function which retains the this binding of the scope it's defined in
this.ships.filter((ship) => {
if (ship.name === shipName) {
ship.direction = direction;
if (ship.location.length > 0) {
redraw = true;
let coordinates = this.getCoordinatesOfShip(ship.name);
}
}
});
Another can be to first retain the this reference for the outer function in some other variable and then use that inside the function passed to filter -
var self = this
this.ships.filter(function(ship) {
if (ship.name === shipName) {
ship.direction = direction;
if (ship.location.length > 0) {
redraw = true;
let coordinates = self.getCoordinatesOfShip(ship.name);
}
}
});
Yet another way is to bind that function to the this bound to the outer function -
this.ships.filter(function(ship) {
if (ship.name === shipName) {
ship.direction = direction;
if (ship.location.length > 0) {
redraw = true;
let coordinates = this.getCoordinatesOfShip(ship.name);
}
}
}.bind(this));

How to properly use "this" within nested .each()(s)? (JQuery) [duplicate]

This question already has answers here:
JQuery nested this references [duplicate]
(4 answers)
Closed 7 years ago.
Here's my nested usage of .each:
itemData["segmentos"] = {};
$("[id^='item-segmentos-']").each(function() {
$("[id^='item-tipo-']").each(function() {
itemData["segmentos"][$(outerthis).val()] = $(innerthis).val();
});
});
How can I use the "outerthis" within the scope of the inner .each?
To use the 'outer' this in the inner each() loops, you simply have to cache the 'outer' this in a variable, and then refer to that variable in place of using this within the inner each() loops:
itemData["segmentos"] = {};
$("[id^='item-segmentos-']").each(function() {
var outerThis = $(this);
$("[id^='item-tipo-']").each(function() {
var innerThis = $(this);
itemData["segmentos"][outerThis.val()] = innerThis.val();
});
});
You can assign it to a variable in the outer function. This will form a closure and the inner function will have access to the outer variable:
itemData["segmentos"] = {};
$("[id^='item-segmentos-']").each(function() {
var outerthis = this;
$("[id^='item-tipo-']").each(function() {
itemData["segmentos"][$(outerthis).val()] = $(this).val();
});
});
But note that jQuery passes the index and element as parameters to your callback, which can make for clearer code, e.g.
itemData["segmentos"] = {};
$("[id^='item-segmentos-']").each(function(oIndex, outerElement) {
$("[id^='item-tipo-']").each(function(iIndex, innerElement) {
itemData["segmentos"][$(outerElement).val()] = $(innerElement).val();
});
});

How to detect creation of new global variables?

I want watch for the creation of new global variables in Javascript so that, anytime a global variable is created, an event is fired.
I've heard of the watch() function but that is only for watching for specific variable names. I want a catchall.
If you already know which names pollute your global namespace (see Intercepting global variable definition in javascript), you can use this trick to figure out when does it actually happen:
window.__defineSetter__('someGlobalVar', function() {
debugger;
});
Be sure to have your developer tools open when you run this.
Obviously works only if your browser supports __defineSetter__ but that's true for modern browsers. Also, don't forget to remove your debug code after you've finished.
Found here.
I don't know how to make this work "on demand" as soon as a var is created, but I can suggest a polling approach. In a browser window, all global become a member of the global "window" object. (Because technically, "window" is the "global object"). So you could do something like the following:
1) enumerate all the properties on a window
window.proplist = window.proplist || {};
for (propname in window) {
if (propname !== "proplist") {
window.proplist[propname] = true;
}
}
2) Set a timer to periodically "poll" window for new properties
setInterval(onTimer, 1000);
3) Wake up on the timer callback and look for new props
function onTimer() {
if (!window.proplist) {
return;
}
for (propname in window) {
if (!(window.proplist[propname])) {
window.proplist[propname] = true;
onGlobalVarCreated(propname);
}
}
}
Afaik, .watch() is only SpiderMonkey (Firefox).
I played around with a polling function, I finally came up with this:
var mywatch = (function() {
var last = {
count: 0,
elems: {}
};
return function _REP(cb) {
var curr = {
count: 0,
elems: {}
},
diff = {};
for(var prop in window) {
if( window.hasOwnProperty(prop) ) {
curr.elems[prop] = window[prop]; curr.count++;
}
}
if( curr.count > last.count ) {
for(var comp in curr.elems) {
if( !(comp in last.elems) ) {
diff[comp] = curr.elems[comp];
}
}
last.count = curr.count;
last.elems = curr.elems;
if(typeof cb === 'function')
cb.apply(null, [diff]);
}
setTimeout(function() {
_REP(cb);
}, 400);
};
}());
And then use it like:
mywatch(function(diff) {
console.log('NEW GLOBAL(s): ', diff);
});
Be aware that this only handles new globals. But you can easily extend this for the case last.count > curr.count. That would indicate that global variables were deleted.
You cant have an event fired when some script does var v = 10, but as selbie said, you can poll the window object... I meant to suggest the same, but he beat me to it. Here's my other example... you count how many window objects are there, and execute GlobalVarCreated() function:
var number_of_globals = 0; //last known globals count
var interval = window.setInterval(function(){
var new_globals_count = 0; //we count again
for(var i in window) new_globals_count++; //actual counting
if(number_of_globals == 0) number_of_globals = new_globals_count; //first time we initialize old value
else{
var number_of_new_globals = new_globals_count - number_of_globals; //new - old
if(number_of_new_globals > 0){ //if the number is higher then 0 then we have some vars
number_of_globals = new_globals_count;
for(var i = 0; i<number_of_new_globals; i++) GlobalVarCreated(); //if we have 2 new vars we call handler 2 times...
}
}
},300); //each 300ms check is run
//Other functions
function GlobalVarCreated(){}
function StopInterval(){window.clearInterval(interval);}
You can load up that code in Chrome or FF console only change: function GlobalVarCreated(){console.log("NEW VAR CREATED");} and test it:
var a = 10
b = 10
String NEW VAR CREATED is displayed 2 times.

Categories