As a sample,
I have a object it has the huge no of methods. each method as it own private functions. when i require to refere my object parent, usually i do like this:
var that = this - it works fine.
But in case of huge number is there a way to avoid this?
example:
var x = function () {
return {
init:function () {
this.val = 10;
},
fun1 : function () {
var that = this;
var p = function () {
console.log(this.val) //not works i know
console.log(that.val) //not works
}
},
fun2 : function () {
var that = this;
var p = function () {
console.log(this.val) //not works i know
console.log(that.val) //not works
}
},
fun3 : function () { // it keep grow to 100's..!?
var that = this;
var p = function () {
console.log(this.val) //not works i know
console.log(that.val) //not works
}
}
}
}();
x.init();
Live
Related
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>
I am trying to create a controller in Javascript, which will respond to button clicks and change the view accordingly.
I have a function which works that looks like this:
document.getElementById("reset").onclick = function () {
//do something
};
However, when I try to put the function in a controller object, I get an "unexpected token" error:
var controller = {
this.reset = document.getElementById("reset").onclick = function () {
//do something
};
}
I'm not sure about 2 things:
How to fix this error? (I know its due to scope, but don't know how to fix it in a way that still follows MVC patterns)
Generally speaking, is this a good way to go about creating a controller object? (I'm new to the MVC model, and don't know if I'm following best practices.)
Thanks.
The error is due to that the object cant be declared like that, there are different ways to do it:
var obj1 = {
a : function() {
console.log('obj1');
}
};
var obj2 = function() {
var b = function() {
console.log('obj2');
};
return {
a: b
}
};
var obj3 = function() {
this.a = function() {
console.log('obj3');
}
};
And then use it.
obj1.a; //prints obj1
obj2().a; //prints obj2
new obj3().a; //prints obj3.
About how to structure your objects is opinion based, but i like to do it like this.
var Controller = function() {
this.attachEvents = function() {
document.getElementById("reset").onclick = reset;
}
var reset = function() {
console.log('reset');
};
}
new Controller().attachEvents();
another option is..
var Controller = function() {
this.reset = function() {
console.log('reset');
};
}
var controller = new Controller();
document.getElementById("reset").onclick = controller.reset;
This is not a valid Javascript object structure, but you can do it in following if it works for you
var controller = {
reset : function () {
document.getElementById("reset").onclick = function(){
//do your work here
}
}
}
Logic is completely on you/developer how he/she wants to handle things.
or you can do the binding thing outside, like,
var controller = {
reset : function () {
//what to do to rsest
}
}
and then, bind it elsewhere
//when to run reset method
document.getElementById("reset").onclick = controller.reset;
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;
};
In this example. I need to update friends list from object function.
var MyClass = function () {
this.friends = [];
this.runtime = {
add: function (name) {
this.friends.push(name);
}
}
};
MyClass.prototype.AddFriend = function (name) {
this.runtime.add(name);
};
MyClass.prototype.GetFriends = function () {
return this.friends;
};
How it's possible?
You could also use the bind() method:
var MyClass = function () {
this.friends = [];
this.runtime = {
add: function (name) {
this.friends.push(name);
}.bind(this)
}
};
MyClass.prototype.AddFriend = function (name) {
this.runtime.add(name);
};
MyClass.prototype.GetFriends = function () {
return this.friends;
};
Read more about it here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Like I said in the comments, it makes much more sense to use this.friends.push(name), but if you really have to use that odd runtime function, then you need to save a copy of this to a new variable:
var MyClass = function () {
var _this = this;
this.friends = [];
this.runtime = {
add: function (name) {
_this.friends.push(name);
}
}
};
DEMO
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;
})()
);