I wanted to create a local function variable for a specific use case without polluting my global object scope. I will be calling doThis() multiple times, but want to keep the local counter value.
So, do this:
TaskHandler = {
doThis : function () {
myVariable+= (myVariable) ? var myVariable = 0;
doSomethingWithVariable(myVariable);
// OR
var myVariable = myVariable+=1 || 0;
// OR
var myVariable = (myVariable) ? myVariable+=1 : 0;
}
Instead of:
TaskHandler = {
myVariable : 0,
doThis : function () {
this.myVariable++;
doSomethingWithVariable(this.myVariable);
}
Is this possible?
TaskHandler = {
doThis : function (requirement) {
var track_index = (function () {
var myVariable = 0;
return function () {
++myVariable;
}
})();
doSomethingWithVariable(track_index);
},
}
TaskHandler = {
doThis : function () {
(function () {
console.log('called'); // This is called
var myVariable = 0;
return function () {
++myVariable;
console.log(myVariable); // This is NOT called
}
})();
}
}
Last edit:
TaskHandler = {
someFunction : function (myObject) {
this.doThis(myObject).counter();
},
doThis : function (myObject) {
return {
counter : (function (myObject) {
var myVariable = 0;
return function () {
++myVariable;
console.log('index', myVariable); //not incrementing
}
})(myObject)
}
}
}
You need a closure: a function that is declared within a scope of a local variable, and that therefore "remembers" this variable later on.
For example:
TaskHandler = {
doThis : (function () {
var myVariable = -1;
return function () {
++myVariable;
doSomethingWithVariable(myVariable);
};
})(),
// ... rest of TaskHandler's properties ...
}
(where (function () { ... })() is an immediately-invoked function expression).
You can check if the value is undefined, as such:
TaskHandler = {
doThis: function() {
if (typeof this.myVariable === 'undefined') {
this.myVariable = 0;
}
doSomethingWithVariable(this.myVariable);
}
}
You have to put your var somewhere, but it does not need to be in global scope or as a filed of your object.
Considering you are using plain ES5, in a browser, so I do exclude all the bells and whistles of ES6's new features, you can do something like this:
(function () {
var myVariable = 0;
window.taskHandler = {
doThis : function () {
myVariable++;
doSomethingWithVariable(myVariable);
}
}
})()
So, the myVariable is not exposed and your global object is not "polluted".
Related
Why this is working:
var a = () => {
var print = function(i) { console.log(i); return this; }
var print2 = function(i) { console.log(i); return this; }
return { print:print , print2:print2 }
}
a().print(5).print2(5);
this is also working:
var b = () => {
var print = (i) => { console.log(i); return this; }
return { print:print}
}
b().print('Arrow function works');
while this is not working:
var b = () => {
var print = (i) => { console.log(i); return this; }
var print2 = function(i) { console.log(i); return this; }
return { print:print , print2:print2 }
}
b().print(5).print2(5);
https://jsfiddle.net/Imabot/1gt2kxfh/14/
It's all due to arrow functions behavior(docs)
Step by step explanation:
var b = () => {
// 1
var print = (i) => { console.log(i); return this; }
var print2 = function(i) { console.log(i); return this; }
return { print:print , print2:print2 }
}
const res = b()
// 2
const secondRes = res.print(5)
// 3
secondRes.print2(5);
here print function saves this reference from the outer scope, so this can't be reassigned anymore
now print function is not using this reference that comes from res variable, because this has already been attached to print function above
as a result secondRes is not going to reference to the object that was returned by b function. But it will use this reference that is attached to print function. And finally because secondRes doesn't have print2 property - it throws
Hope it helps <3
In a non-arrow function, the value of this depends on how the function is called. If the function is called as a member of an object, this refers to this object:
someObj.myFunction() // inside myFunction this will point to someObj
In contrast, the arrow functions do not affect this. So whithin an arrow function the value of this is whatever it is in the enclosing scope.
The answer from Lex82 gives the why. If you want to return the functions, so you can use function chaining:
var b = () => {
var print = (i) => { console.log(i); return { print:print , print2:print2 }; }
var print2 = function(i) { console.log(i); return this; }
return { print:print , print2:print2 }
}
b().print(5).print2(5);
So I have 3 functions.
What i want to achieve is to take value from one function which is nested in parent function, and the pass it as the argument in third function.
And can this be achieved with closer, and how ?
Thanks so much.
function foo () {
var rand = 10;
function bar() {
return {
age:rand;
}
}
}
function addValue(arg) {
console.log(bar());
}
Call as below
function foo () {
var rand = 10;
return function bar() {
return {
age:rand
}
}();
}
function addValue(arg) {
console.log(foo());
}
Edited
function foo (func) {
var rand = 10;
function bar() {
return {
age:rand
}
};
//Do your stuff
return eval(func+"()");
}
function addValue(arg) {
console.log(foo("bar"));
}
You can instead assign the function to the parent object and call it like this.
function foo(){
var rand = 10;
this.bar = function(){
return {age: rand};
}
}
var obj = new foo();
function addVal() {
console.log(obj.bar());
}
addVal();
Can someone advise me on below Javascript -
1) How can I use the "Base" variable?
2) In callShowMsg function, a local variable "ns" is used to alias the namespace.
Is it possible to use a global variable to alias the namespace? It will avoid the need to declare local variable in each function.
Thanks in advance.
My code is,
var Base = namespace("MyCo.MyApp.Myprogram");
MyCo.MyApp.Myprogram =
{
showMsg: function (pMsg)
{
alert(pMsg);
},
callShowMsg: function (pMsg)
{
var ns = MyCo.MyApp.Myprogram;
ns.showMsg('Hello');
}
}
something like this: (YUI with some fallback for custom namespace). Though I believe you do not have to "namespace" or reference the obj. Just refer to it as "this".
So, if you are within the obj, you can call the methods like so: this.showMsg('somevalue')
function createNamespace() {
var uniqueNS = "MyCo";
var a = arguments, o, i = 0, j, d, arg,
ns = this,
PERIOD = ".";
// force namespace to MyCo
ns.uniqueNS = ns.uniqueNS || {};
ns = ns.uniqueNS;
for (; i < a.length; i++) {
o = ns; //Reset base object per argument or it will get reused from the last
arg = a[i];
if (arg.indexOf(PERIOD) > -1) { //Skip this if no "." is present
d = arg.split(PERIOD);
for (j = (d[0] == uniqueNS) ? 1 : 0; j < d.length; j++) {
o[d[j]] = o[d[j]] || {};
o = o[d[j]];
}
} else {
o[arg] = o[arg] || {};
o = o[arg]; //Reset base object to the new object so it's returned
}
}
return o;
}
var Base = createNamespace("MyCo.MyApp.Myprogram");
Base =
{
showMsg: function (pMsg)
{
alert(pMsg);
},
callShowMsg: function (pMsg)
{
this.showMsg(pMsg);
}
}
Base.showMsg('ok');
I dont think there is some function like namespace like you wrote above,
You can do something like that:
var MYAPPLICATION = {
calculateVat: function (base) {
return base * 1.21;
},
product: function (price) {
this.price = price;
this.getPrice = function(){
return this.price;
};
},
doCalculations: function () {
var p = new MYAPPLICATION.product(100);
alert(this.calculateVat(p.getPrice()));
}
}
Or If you want to use nested namespaces you can try this:
var MYAPPLICATION = {
MODEL: {
product: function (price) {
this.price = price;
this.getPrice = function(){
return this.price;
};
}
},
LOGIC: {
calculateVat: function (base) {
return base * 1.21;
},
doCalculations: function () {
var p = new MYAPPLICATION.MODEL.product(100);
alert(this.calculateVat(p.getPrice()));
}
}
}
How can I use the "Base" variable?
That is going to depend on what value got returned by the namespace function. This is not a standard JS function and its probably specific to the libraries you are using so I cant answer.
Is it possible to use a global variable to alias the namespace?
Of course.
var ns = {
callShowMsg: function (pMsg)
{
ns.showMsg('Hello');
}
}
MyCo.MyApp.Myprogram = ns;
You can also make ns into a local function instead of a global by putting it inside an initialization functions intead of putting it on the script toplevel. The most common way of doing that is using an immediately invoked anonymous function:
(function(){
var ns = {
callShowMsg: function (pMsg)
{
ns.showMsg('Hello');
}
}
MyCo.MyApp.Myprogram = ns;
}());
In the following code snippet, 'this.x()' can only be called in case 2 (see main()).
Also Bar unequals this in case 1, but is equal for case 2.
function Class_Bar() {
this.panel = null;
this.init = function () {
// do some stuff
this.panel = 20;
}
this.apply = function () {
alert(Bar == this);
Bar.x();
this.x();
}
this.x = function() {
alert("Some friendly message");
alert(Bar.panel);
}
}
var Bar = new Class_Bar();
function Class_Factory() {
this.factories = new Array();
this.add = function (init, apply) {
this.factories.push({"init":init, "apply":apply});
}
this.init = function () {
for (var i = 0; i < this.factories.length; ++i) {
this.factories[i]["init"]();
}
}
this.apply = function () {
for (var i = 0; i < this.factories.length; ++i) {
this.factories[i]["apply"]();
}
}
}
var Factory = new Class_Factory();
function main() {
// Case 1
Factory.add(Bar.init, Bar.apply);
Factory.init();
Factory.apply();
// Case 2
Bar.init();
Bar.apply();
}
main();
http://pastebin.com/fpjPNphx
Any ideas how to "fix" / workaround this behaviour?
I found a possible solution, but it seems to be a "bad" hack.: Javascript: How to access object member from event callback function
By passing Bar.init, you're really only passing the function but not the information that it belongs to Bar (i.e. what the this value should be). What you can do is binding that information:
Factory.add(Bar.init.bind(Bar), Bar.apply.bind(Bar));
var objs = new Array();
function Foo(a) {
this.a = a
$("#test").append($("<button></button>").html("click").click(this.bar));
}
Foo.prototype.bar = function () {
alert(this.a);
}
$(document).ready(function () {
for (var i = 0; i < 5; i++) {
objs.push(new Foo(i));
}
});
is it possible to make it so that when a button is clicked,
it returns corresponding Foo.a value (from Foo obj that created the button)?
The #Khnle's answer is close, but with that approach you need an anonymous function to use the self reference:
function Foo(a) {
this.a = a;
var self = this;
$("#test").append($("<button></button>").html("click").click(function () {
self.bar(); // correct `this` value inside `bar`
}));
}
You can also use the $.proxy method, to preserve the object context:
function Foo(a) {
this.a = a
$("#test").append($("<button></button>")
.html("click")
.click($.proxy(this.bar, this)));
}
Check the above example here.
Inside your click handler, this no longer refers to the Foo object, but the element where click takes place, which is the button element in this case. So one way to fix it is as follow:
function Foo(a) {
this.a = a;
var self = this;
$("#test").append($("<button></button>").html("click").click(self.bar));
}
Here's more jQuery style (no global objs or Foos)
(function ($) {
$.fn.aghragbumgh = function (settings) {
var config = { 'a': 0 };
if (settings) $.extend(config, settings);
var bar = function () {
alert(config.a);
}
this.each(function () {
$(this).append($("<button></button>").html("click").click(bar));
});
return this;
};
})(jQuery);
$(document).ready(function () {
for (var i = 0; i < 5; i++) {
$('#test').aghragbumgh({ 'a': i });
};
});
Html:
<div id="test"></div>