"this" returning a function instead of object - javascript

In the below javascript code I wanted to know which object does "this" point to.But instead I am getting a function.
I thought "this" always referred to the object calling that function.
So can anyone explain why this behaviour ?
$(document).ready(function() {
var Paper = function() {};
Paper.prototype = {
populate: function(data) {
data.questions.forEach(function(entry) {
//printing a function instead of object
console.log(this);
}.bind(this));
}
};
var paperDataLoader = function() {
this.callbacks = [];
};
paperDataLoader.prototype = {
//accepts a callback to notify the registered function
registerDataLoaded: function(callback) {
this.callbacks.push(callback);
},
//calls the callback functions when data is loaded
loadData: function() {
$.ajax('../find_paper.php', {
method: 'POST',
contentType: 'text'
}).done(function(ajaxData) {
this.paperData = $.parseJSON(ajaxData);
for (var i = 0; i < this.callbacks.length; i++)
this.callbacks[i](this.paperData);
}.bind(this));
}
};
var loader = new paperDataLoader();
var paper = new Paper();
loader.registerDataLoaded(paper.populate);
loader.loadData();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

It's working for me:
var Paper = function() {};
Paper.prototype = {
populate: function(data) {
data.questions.forEach(function(entry) {
console.log(this);
}.bind(this));
}
};
var paper = new Paper();
paper.populate({ questions: [ 1 ] }); // prints paper object
Maybe you're re-binding paper.populate somewhere?

Related

Convert string to an existing function?

Take this code:
var john = new function () {
var init = function () {
alert("John")
};
return {
init: init
};
};
var jane = new function () {
var init = function () {
alert("Jane")
};
return {
init: init
};
};
function callInit(person) {
var fn = new Function(person); // does not work!
fn.init();
}
$(document).ready(function () {
callInit("john");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I would like to pass a string to a function - in my example I pass the string "john". Then I need to convert the passed string to the existing function and call init - in my example call john.init()
Is it possible?
Thanks
You can do it by changing your callInit function to:
function callInit(person) {
var fn = window[person];
fn.init();
}
var john = new function () {
var init = function () {
alert("John")
};
return {
init: init
};
};
var jane = new function () {
var init = function () {
alert("Jane")
};
return {
init: init
};
};
function callInit(person) {
var fn = window[person];
fn.init();
}
$(document).ready(function () {
callInit("john");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
One way to achieve this would be by placing the data structures you want to access by key in to an object. You can then use the string passed in to your function as an argument to access that object by key, the advantage being that you avoid using global variables, which pollute the window. It would look like this:
let people = {
john: function() {
var init = function() {
console.log("John")
};
return { init: init };
},
jane: function() {
var init = function() {
console.log("Jane")
};
return { init: init };
}
}
function callInit(person) {
var fn = people[person]();
fn.init();
}
$(document).ready(function() {
callInit("john");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Note that if you are going to be using a repeated data structure in this manner I would strongly suggest creating a reusable class for each property within the object. That would look something like this:
class Person {
constructor(name) {
this.name = name;
}
greeting() {
console.log(`Hello, my name is ${this.name}`);
}
}
let people = {
john: new Person('John'),
jane: new Person('Jane')
}
function callInit(person) {
var fn = people[person];
fn.greeting();
}
$(document).ready(function() {
callInit("john");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Javascript inheritance is not working

Facing inheritance problem in this below code i am new to OOPS concepts please help me.
var testA = function() {
this._data = undefined
};
testA.prototype.init = function(data) {
this._data = data;
};
testA.prototype.get = function(data) {
if (this._data) {
return data
}
};
var testB = function() {}
testB.prototype = Object.create(testA);
var instance = new testB();
testB.prototype.init = function(data) {
testA.prototype.init.call(this, data);
};
testB.prototype.Somedata = function() {
testA.prototype.get();
}
instance.init("testdata");
instance.Somedata() // here i am getting this._data is undefined
When i call instance.init("testdata") now it's setting value to this._data in the parent.
When i call instance.Somedata() here i am getting undefined
May i know what could be reason? and how can i get the this._data value when i call instance.Somedata().
At first:
testB.prototype = Object.create(testA);
Instantiates a function, you may want to either instantiate the prototype:
testB.prototype = Object.create(testA.prototype);
or construct it directly:
testB.prototype =new testA;
Secondly SomeData is not returning anything, may do so and you also need to keep the context:
testB.prototype.Somedata = function() {
return testA.prototype.get.call(this,"return");
}
Or even easier if we did the upper inheritance right:
testB.prototype.Somedata = function() {
return this.get("return");
}
Your using Object.create against a constructor, you should use it against an instance, otherwise, you get a function in return instead of an object.
var TestA = function() {
this._data = undefined;
};
TestA.prototype.init = function(data) {
this._data = data;
};
TestA.prototype.get = function() {
return this._data;
};
var instance = Object.create(new TestA());
instance.init('some');
instance.get();

Set variable to function but that function should not get executed

I am setting some variable in someMethod1 and want to pass that variable to someMethod2. Here I just want to set variable to someMethod2 function but that method should not get called. It needs to be called later on some event(click). How can I achieve this one? Please help me.
someMethod1 = function() {
var test = "testText";
someMethod2(test)
};
someMethod2 = function(check) {
var a = check;
};
You can do it with saving variable in global scope:
var sharedVars = {};
function someMethod1() {
sharedVars.a = 'testText';
}
function someMethod2(check) {
var a = (check)? check : sharedVars.a;
}
or creating some object that stores and returns value by key:
var sharedStorage = {
data: {},
set: function(key, value) {
this.data[key] = value;
return this;
},
get: function(key, fallback) {
return this.data[key] || fallback;
}
};
function someMethod1() {
sharedStorage.set('a', 'testText');
}
function someMethod2() {
var a = sharedStorage.get('a');
}
Declare var test outside, then set it inside someMethod1(). Now you can call someMethod2() on a click event and set test to a.
var test;
someMethod1 = function() {
test = "testText";
};
someMethod2 = function() {
var a = test;
};

JavaScript Event implementation to Closure based Object

I have a Object based on some closure, and want to implement event scheme here:
var class1 = function(val1)
{
var val = val1;
//------ want to call a method of Object of class1--------
var self = this;
setTimeout(function()
{
self.onEvent();
}, 1000);
//----------------
return {
f1: function()
{
return val;
},
onEvent: function()
{
console.log('not implemented yet. Override');
}
};
};
var obj1 = class1(5);
console.log(obj1.f1()); //5
obj1.onEvent(); //not implemented yet. Override
obj1.onEvent = function()
{
console.log('event fired');
}
got error, and I know the reason, and I need a solution:
5
not implemented yet. Override
/....../app.js:9
self.onEvent();
^
TypeError: Object #<Object> has no method 'onEvent'
It is possible if this bind with addEventListener scheme like this:
(The idea based on
Implementing events in my own object
)
var class2 = function()
{
var _this = this;
_this.events = {};
var fireEvent = function(name, args)
{
if (!_this.events.hasOwnProperty(name)) return;
if (!args || !args.length) args = [];
var evs = _this.events[name];
var l = evs.length;
for (var i = 0; i < l; i++)
{
evs[i].apply(null, args);
}
};
setTimeout(function()
{
fireEvent('testEvent', ['hello'])
}, 1000);
return {
addEventListener: function(name, handler)
{
if (_this.events.hasOwnProperty(name))
_this.events[name].push(handler);
else
_this.events[name] = [handler];
}
};
};
var obj2 = class2();
obj2.addEventListener('testEvent',
function(data)
{
console.log('event fired: ' + data);
});
event fired: hello
However, I prefer not to use addEventListener but .onEvent() scheme.
Is it possible? Perhaps it is possible using call/apply.
Thanks for your advice.
In your first block of code, you are returning an object, which is different from this or self.
You don't necessarily have to return this in your constructors but you should assign your functions on the returned object. If you create a variable for the object you want to return, you can use it in your setTimeout callback like so:
var class1 = function(val1)
{
var val = val1;
var obj = {
f1: function()
{
return val;
},
onEvent: function()
{
console.log('not implemented yet. Override');
}
};
setTimeout(function()
{
obj.onEvent();
}, 1000);
return obj;
};
For extra style points, you might want to capitalize the name of your constructors (and perhaps use new to instantiate them to make things clearer to your readers).

jQuery callback into non-jQuery parent object

See this code:
var MyObject = new function() {
this.tos = new Array();
this.show = function() {
this.clearTimeouts();
$("#divExample").slideDown(null,function() {
MyObject.tos[MyObject.tos.length] =
setTimeout(function(){MyObject.doSomething();} , 1800);
});
return;
};
this.doSomething = function() {
return;
};
this.clearTimeouts = function(){
for (var i=0; i<this.tos.length; i++)
clearTimeout(this.tos[i]);
this.tos = new Array();
return;
};
}
MyObject and it's methods are used in a few places. Maybe it's a bad way to do it, I dunno. I didn't want to tie it too closely with jQuery for my own reasons, so leaving it like this made sense as I can easily change the slide to style.display.
The problem is that I dont like referencing the object as MyObject in the callback of the jQuery slide, but I have to to add the timeout reference to my array of them so they can all be cleared. Is there a better way to do this?
Thanks!
You could try something like this:
this.show = function() {
var obj = this;
obj.clearTimeouts();
$("#divExample").slideDown(null,function() {
obj.tos[obj.tos.length] =
setTimeout(function(){obj.doSomething();} , 1800);
});
return;
};
var MyObject = (function() {
// private variable
tos = new Array();
// private method
function doSomething() {
// do something
// ..
}
// return an instance with public methods
return {
show: function() {
this.clearTimeouts();
$("#divExample").slideDown(null,function() {
tos[tos.length] =
setTimeout(function(){ doSomething(); } , 1800);
});
},
clearTimeouts: function() {
for (var i=0; i<tos.length; i++)
clearTimeout(tos[i]);
tos = new Array();
}
}
}​;​

Categories

Resources