Using this inside an Javascript IIFE within an object - javascript

I would like to use this instead of the name of the object inside the IIFE.
var ops = {
start: (function (){
socket.on('set', function(data) {
ops.getData();
});
}()),
getData: function (){
...
}
};
How it can be done?

You cannot. Not to mention that your function does not return anything to assign to ops.start.
var ops = {
start: function (){
var self = this;
socket.on('set', function(data) {
self.getData();
});
}
};
ops.start();

You could use getter and closure on your function context if needed. Getter automatically invokes a function:
var ops = {
get start() {
return socket.on('set', function(data) {
ops.getData();
});
},
getData: function (){
}
};
Now you can just refer to ops.start

You can create a new object and use it's prototype to access "this":
var o = Object.create(Object.prototype, {
data: {
value: 12
},
getobject: {
get: function() {
return this.data;
}
}
});
o.getobject;

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>

Call back function using `this` in Jquery get()

I want to use this keyword in the callbacks of $.get(). My code structure is
var myObject = {
get: function() {
$.get(server,data,function(data,status) {
this.callback();
});
},
callback: function() {
}
}
I don't want to use myObject.callback(). Is there any way to accomplish using this.callback()?
You can .bind() the value of this to your callback function before passing it to $.get():
var myObject = {
get: function() {
$.get(server, data, function(data, status) {
this.callback();
}.bind(this));
}
callback: function {
// do something here
}
}
Of course, that assumes the value of this within your own myObject.get() function is correct, which it would be if you called it with "dot notation" as myObject.get().
Note also that if the only thing your anonymous function does is call the other function then you can bind the other function directly:
var myObject = {
get: function() {
$.get(server, data, this.callback.bind(this));
}
callback: function {
// do something here
}
}
Option #1 -- cache this in a variable (_this):
var myObject = {
get: function() {
var _this = this;
$.get(server, data, function(data, status) {
_this.callback(); // this keyword refers to Window obj not myObject
});
}
callback: function {
// do something here
}
}
Option #2 -- use jQuery's .proxy method:
var myObject = {
get: function() {
$.get(server, data, $.proxy(function(data, status) {
_this.callback(); // this keyword refers to Window obj not myObject
}), this);
}
callback: function {
// do something here
}
}
(Edited-- thanks nnnnnn)

How can I access the base class variable in javascript from json function

My code is work Like https://jsfiddle.net/89vpLxxy
I have create two function inside the function one is normal function and another one is json function, I can access the base class variable from the normal function but not from json function. How can I access the variable?
I have tried shown below
<script>
var funvar=function(A)
{
alert(A);
this.name = "Merbin Joe";
this.fun1=function()
{
alert(this.name);
},
this.colanfun= {
saveScore:function () {
alert("HHHHHH : "+this.name);
}
}
}
var Obj = new funvar();
Obj.fun1();
Obj.colanfun.saveScore();
</script>
Inside your JSON function, this keyword refers to colafun instead of your outer function scope (i.e funvar). You can store the reference of this in a variable self and you can access it.
var funvar=function()
{
var self = this;
this.name = "Merbin Joe";
this.fun1=function()
{
alert(this.name);
},
this.colanfun= {
saveScore:function () {
alert("HHHHHH : "+self.name); //Here How Can I access
}
}
}
There is no such thing as 'JSON function', but this is what you want:
You need to bind the function to this See bind doc from Mozilla DN
var funvar=function()
{
this.name = "Merbin Joe";
this.fun1=function()
{
alert(this.name);
},
this.colanfun= {
saveScore:function () {
alert("HHHHHH : "+this.name); //Here How Can I access
}.bind(this)
}
}
var Obj = new funvar();
Obj.fun1();
Obj.colanfun.saveScore();
See demo here: https://jsfiddle.net/laruiss/89vpLxxy/1/
var funvar=function(A)
{
var that = this;
alert(A);
that.name = "Merbin Joe";
that.fun1=function()
{
alert(that.name);
},
that.colanfun= {
saveScore:function () {
alert("HHHHHH : "+that.name);
}
}
}
var Obj = new funvar();
Obj.fun1();
Obj.colanfun.saveScore();
You can generate your function with closure such as this code:
this.colanfun= {
saveScore:(function(parent) { return function () {
alert("HHHHHH : "+parent.name); //Here How Can I access
}; }(this))
}

Public function in Singleton calling itself

I'm trying to use a singleton pattern but I am having trouble with implementing a recursive public function.
var singleton = (function(){
var self = this;
function privateFunc(){
console.log('I can only be accessed from within!');
}
return{
publicFunc: function(){
//More stuff here
setTimeout(self.publicFunc, 1000);
}
}
})();
I am calling it with singleton.publicFunc
I get this error Uncaught TypeError: Cannot call method 'publicFunc' of undefined.
My understanding is var self is actually the Window object in this instance, so I have to pass singleton.publicFunc as the callback for this to work, but it doesn't seem very "DRY" (Don't repeat yourself). Is there
a better way to accomplish this while using a singleton?
With API calls
var wikiAPI = (function(){
var self = this;
return {
getRandomArticle : function() {
return $.getJSON("http://en.wikipedia.org/w/api.php?action=query&generator=random&grnnamespace=0&prop=extracts&exintro=&format=json&callback=?", function (data) {
});
},
fireAPICalls : function() {
self.getRandomArticle().done(function(data) {
for(var id in data.query.pages) {
this.data = data.query.pages[id];
}
console.log(this.data);
setTimeout(self.fireAPICalls, 1000);
});
}
}
})();
You can use a named function expression like so:
var singleton = (function(){
var self = this;
function privateFunc(){
console.log('I can only be accessed from within!');
}
return{
publicFunc: function nameVisibleOnlyInsideThisFunction(){
//^-------------------------------^
//More stuff here
setTimeout(nameVisibleOnlyInsideThisFunction, 1000);
}
}
})();
I just saw your edit. What would help is having a reference to the functions you are trying to call. So how about something like this:
var wikiAPI = (function(){
var self = this;
var randomArticle = function() {
return $.getJSON("http://en.wikipedia.org/w/api.php?action=query&generator=random&grnnamespace=0&prop=extracts&exintro=&format=json&callback=?", function (data) {
});
};
var repeatFunc = function fireApi() {
randomArticle().done(function(data) {
for(var id in data.query.pages) {
this.data = data.query.pages[id];
}
console.log(this.data);
setTimeout(fireApi, 1000);
});
};
return {
getRandomArticle : randomArticle,
fireAPICalls : repeatFunc
}
})();
Use bind in the setTimeout() to bind the function to the right scope:
publicFunc: function() {
setTimeout(this.publicFunc.bind(this), 1000);
}
Demo: http://jsfiddle.net/te3Ru/
You can't use this in a IIFE. If you want to use this properly you need to create an object/instance of a function, like so:
var singleton = (function () {
// allow to omit "new" when declaring an object
if (!(this instanceof singleton)) return new singleton();
var self = this, // self now points to "this"
privateFunc = function () {
console.log('I can only be accessed from within!');
};
this.publicFunc = function() {
console.log(this); // this now points to the correct object
setTimeout(function () {
self.publicFunc.call(self); // call function in the "self" scope
}, 1000);
};
return this;
});
singleton().publicFunc();
it's not much of a singleton now, but you can have the closest thing to private and public that javascript has!

Accessing a containing object from with in its method?

In the snippet below, an object literal holds properties, one of which is a method that needs access to the the object literal.
However, b.c. it is only used as an event handler callback, this always points to the element that triggered the event.
I need to access the containing object.
Otherwise, I'm forced to put a function in a function which seems odd.
/***************************************************************************************************
**MSimMenu - simple drop down menu
*/
NS.parsel({
Name: 'MSimMenu',
E: {
hold_name: '#hold_name',
wrap_bottom: '#wrap_bottom'
},
A: {
time_out_id: null,
TIME_DELAY: 1000
},
// in mouseout this points to the element that triggered the event
// need access to containing object
mouse_out: function () {
this.A.time_out_id = NS.setTimeout(this.hideBottom, this.A.TIME_DELAY);
},
init: function () {
var self = this;
// tempoaray fix - function in function seems odd
function mouse_out() {
self.A.time_out_id = NS.setTimeout(self.hideBottom, self.A.TIME_DELAY);
}
self.E.hold_name.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
self.showBottom();
}, false);
self.E.wrap_bottom.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
}, false);
self.E.wrap_bottom.addEventListener("mouseout", mouse_out, false);
self.E.hold_name.addEventListener("mouseout", mouse_out, false);
},
showBottom: function () {
this.E.wrap_bottom.style.visibility = 'visible';
},
hideBottom: function () {
this.E.wrap_bottom.style.visibility = 'hidden';
}
});
Final Code Using Bind
NS.parsel({
Name: 'MSimMenu',
E: {
hold_name: '#hold_name',
wrap_bottom: '#wrap_bottom'
},
A: {
time_out_id: null,
TIME_DELAY: 1000
},
init: function () {
var self = this;
self.E.hold_name.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
self.showBottom();
}, false);
self.E.wrap_bottom.addEventListener("mouseover", function () {
NS.clearTimeout(self.A.time_out_id);
}, false);
self.E.wrap_bottom.addEventListener("mouseout", self.mouse_out.bind(self), false);
self.E.hold_name.addEventListener("mouseout", self.mouse_out.bind(self), false);
},
mouse_out: function () {
this.A.time_out_id = NS.setTimeout(this.hideBottom, this.A.TIME_DELAY);
},
showBottom: function () {
this.E.wrap_bottom.style.visibility = 'visible';
},
hideBottom: function () {
this.E.wrap_bottom.style.visibility = 'hidden';
}
});
I have seen alot of people create a variable to assign the object to and then use the variable.
var that = {
myfunc:function(){
console.log(that)
}
};
NS.parsel(that);
I actually like moving most of the logic into the init method. Provides nice encapsulation with an easy way to declare public and private methods/variables. For example:
NS.parsel({
init: function() {
var self = this;
//public instance variable
self.Name = 'MSimMenu';
//private instance variables
var A = {
time_out_id: null,
TIME_DELAY: 1000
};
var E = {
hold_name: '#hold_name',
wrap_bottom: '#wrap_bottom'
};
//public instance method
self.showBottom = function () {
E.wrap_bottom.style.visibility = 'visible';
};
//private instance method
E.wrap_bottom.addEventListener("mouseout", mouse_out, false);
function mouse_out() {
A.time_out_id = NS.setTimeout(self.hideBottom, A.TIME_DELAY);
}
}
});
There's a lot of ways you can get what you want.
One trick you can do is to not use the mouse_out function directly, but provide a helper function like get_mouse_out() that returns a bound version of the function.
var myobject = {
data:"Some data",
_mouse_out: function() { console.log(this.data); }
get_mouse_out: function() {
var self = this;
return function(){ return Function.apply(self._mouse_out,self,arguments); }
}
}
//Example call back using function.
function do_callback(fn) { fn(); }
//This doesn't work.
do_callback( myobject._mouse_out);
//But this does
do_callback( myobject.get_mouse_out() );
EDIT: Improved version inlining _mouse_out and using bind.
var myobject = {
data:"Some data",
get_mouse_out: function() {
function _mouse_out() { console.log(this.data); }
return _mouse_out.bind(this);
}
}
//Example call back using function.
function do_callback(fn) { fn(); }
//But this does
do_callback( myobject.get_mouse_out() );
If you're willing to have init be called as setup before mouse_out is used then you can do this.
var myobject = {
data:"Some data",
init: function() {
function _mouse_out() { console.log(this.data); }
this.mouse_out = _mouse_out.bind(this);
}
}
myobject.init();
fn( myobject.mouse_out );
Finally there's a nice variant on Shanimals that works a similar way, but provides encapsulation.
NS.parcel( (function(){
var myobj = {};
myobj.data = "Some data";
myobj.mouse_out = function(){ console.log(myobj.data); }
return myobj;
})()
);

Categories

Resources