Can't have access to a variable using call in Javascript - javascript

I'm studying Javascript and learning how to use call. I created this script and I don't know why I can't have access to this variable Time.
var MyObject;
(function(MyObject) {
var Runner = (function() {
function Runner(time) {
this.time = time;
}
var myFunctionArray = [];
Runner.prototype.execute = function() {
myFunctionArray[0]();
}
Runner.prototype.newTest = function(index, execute) {
var test = function() {
return execute.call(this);
}
myFunctionArray.push(test);
}
return Runner;
})();
MyObject.Runner = Runner;
})(MyObject || (MyObject = {});
var myNewObj = new MyObject.Runner(1000); myNewObj.newTest('1', function() {
console.log(this.time) //output: undefined
});
So how can I get time value inside newTest function?

Issue is in newTest function
Runner.prototype.newTest = function(index, execute) {
var test = function() {
return execute.call(this);
}
myFunctionArray.push(test);
}
Here this is pointing to test and not Runner. You will have to save context in a variable and then set it in call.
Runner.prototype.newTest = function(index, execute) {
var self = this;
var test = function() {
return execute.call(self);
}
myFunctionArray.push(test);
}
.call + self
var MyObject;
(function(MyObject) {
var Runner = (function() {
function Runner(time) {
this.time = time;
}
var myFunctionArray = [];
Runner.prototype.execute = function() {
myFunctionArray[0]();
}
Runner.prototype.newTest = function(index, execute) {
var self = this;
var test = function() {
return execute.call(self);
}
myFunctionArray.push(test);
}
return Runner;
})();
MyObject.Runner = Runner;
})(MyObject || (MyObject = {}));
var myNewObj = new MyObject.Runner(1000);
myNewObj.newTest('1', function() {
console.log(this, this.time) //output: undefined
});
myNewObj.execute()
.bind
As commented, you can even use .bind
var MyObject;
(function(MyObject) {
var Runner = (function() {
function Runner(time) {
this.time = time;
}
var myFunctionArray = [];
Runner.prototype.execute = function() {
myFunctionArray[0]();
}
Runner.prototype.newTest = function(index, execute) {
myFunctionArray.push(execute.bind(this));
}
return Runner;
})();
MyObject.Runner = Runner;
})(MyObject || (MyObject = {}));
var myNewObj = new MyObject.Runner(1000);
myNewObj.newTest('1', function() {
console.log(this, this.time) //output: undefined
});
myNewObj.execute()

When you declare your Runner function, you've actually declared a function that takes no arguments that then itself declares a function called Runner that takes one argument.

Actually In this code snippet :
Runner.prototype.newTest = function(index, execute) {
var test = function() {
return execute.call(this);
}
myFunctionArray.push(test);
}
this will reference to test variable (as per constructor invocation pattern)
So, to pass right variable cache the value of this in another variable and then pass that to function.

Related

Namespace With New Instance On Each Call

I'm trying to create something similar to d3(ex: d3.select()) but much more simple and I need to have a new instance each time I call the namespace function. Is this possible and/or am I approaching this wrong?
var dom = new function () {
var Element = null;
this.select = function (query) {
Element = document.querySelector(query);
return this;
};
this.append = function (elem) {
Element.append(elem);
return this;
};
};
Desired use
var bodyelement = dom.select("body");
var p = dom.select("p");
You need to run some code each time you use the dom object. So if the dom object was a function, you could call it to get a new instance.
var dom = function () {
var Element = null;
var newdom = {};
newdom.select = function (query) {
Element = document.querySelector(query);
return this;
};
newdom.append = function (elem) {
Element.append(elem);
return this;
};
return newdom;
};
console.log(dom() === dom(), "(false means the instances are different)");
var dom = new function () {
var Element = null;
this.select = function (query) {
Element = document.querySelector(query);
return this;
};
this.append = function (elem) {
Element.append(elem);
return this;
};
// add a way of accessing the resulting Element
this.element = function() { return Element; }
};
console.log(dom.select("body").element());
console.log(dom.select("p").element());
<p>blah</p>

JavaScript object inheritance issue

I'm a beginner with JavaScript Objects and Prototypes and trying to develop my first " multi-level inherited" JS Objects, an unexpected issue came up.
This is my code:
var Utils = function () {};
Utils.prototype = {
sayHelloGeneral: function(){
console.log('hello');
}
};
var FormTools = function () {
Utils.call(this);
this.fields = [];
};
FormTools.prototype = Object.create(Utils.prototype);
FormTools.prototype.constructor = FormTools;
FormTools.prototype.sayHelloForm= function (fields) {
console.log('hello form');
};
function GroupManager(value) {
FormTools.call(this);
this.val = typeof values === 'undefined' ? 1 : value;
};
GroupManager.prototype = Object.create(FormTools.prototype);
GroupManager.prototype.constructor = GroupManager;
GroupManager.prototype.helloGroupManager= function (givenValue) {
console.log('Hello group manager');
};
Why when I try to call the group manager, it prints only the sayHelloGeneral function?
var GM = new GroupManager;
GM.sayHelloGeneral(); //->ok
GM.helloGroupManager(); //--> ok
GM.sayHelloForm(); //->sayHelloForm is not a function
It seems to be working fine. See the snippet below
var Utils = function () {};
Utils.prototype = {
sayHelloGeneral: function(){
console.log('hello');
}
};
var FormTools = function () {
Utils.call(this);
this.fields = [];
};
FormTools.prototype = Object.create(Utils.prototype);
FormTools.prototype.constructor = FormTools;
FormTools.prototype.sayHelloForm= function (fields) {
console.log('hello form');
};
function GroupManager(value) {
FormTools.call(this);
this.val = typeof values === 'undefined' ? 1 : value;
};
GroupManager.prototype = Object.create(FormTools.prototype);
GroupManager.prototype.constructor = GroupManager;
GroupManager.prototype.helloGroupManager= function (givenValue) {
console.log('Hello group manager');
};
var GM = new GroupManager;
//GM.sayhello(); //->ok---> should be sayHelloGeneral()
GM.sayHelloGeneral();
GM.helloGroupManager(); //--> ok
GM.sayHelloForm(); //->Works fine too

Pass reference of main object to another object

I created this simplified version of some code I'm dealing with. I need to figure out how to pass a reference of an instantiated object to another object that has been created by this object. I can't get the reference to the main object "self" to be passed to the second object and actually be able to call a function on it. Hopefully the code will make it more clear:
var app = app || {};
(function (m, $, undefined) {
m.Counter = function () {
var self = this;
var pub = {};
pub.total = 0;
pub.add = function () {
pub.total++;
};
pub.subtract = function () {
pub.total--;
};
pub.status = function () {
console.log(pub.total);
};
pub.spawn = function () {
var sp = new app.modules.Obj(self);
return sp;
};
return pub;
};
m.Obj = function (counter) {
var pub = {};
pub.add = function () {
counter.add();
};
return pub;
};
}(app.modules = app.modules || {}));
var c = new app.modules.Counter();
c.add();
c.add();
c.add();
c.status();
d = c.spawn();
d.add();
c.status();
What I would want to have happen is that d.add() would increment the total of c. So the output would be 3 for the first c.status() call and then 4 for the output of the second c.status();

How to "new" a returned function in Javascript

I am trying to simulate a namespace feature in Javascript.
var com = {};
com.domain = {};
com.domain.system = {};
com.domain.net = {};
com.domain.net.ip = {};
com.domain.net.ip.tcp = {};
com.domain.net.ip.udp = {};
com.domain.net.ip.ssl = {};
com.domain.util = {};
com.domain.util.timer = {};
com.domain.plugins = {};
com.domain.session = {};
com.domain.io = {};
com.domain.algorithm = {};
com.domain.debug = {};
This is the namespaces declaration. Later I will add functions to these namespaces.
This is my selector function:
For a convenient way to use namespaces, I add a function named $. This function will walk all namespaces in com. If the selected name exists, return the object.
function $ (selector) {
function digger (namespace, selector) {
for (var prop in namespace) {
if (typeof namespace[prop] == "array" || typeof namespace[prop] == "object") {
if (prop == selector) {
return namespace[prop];
}
var dig = digger(namespace[prop], selector);
if (dig != null) {
return dig;
}
} else {
if (prop == selector) {
return namespace[prop];
}
}
}
}
return digger (com, selector);
}
After that, I add a timer to namespace com.doamin.util.
com.domain.util.timer = function () {
this._handle = new InnerObj.SystemTimer(io);
return this;
};
com.domain.util.timer.prototype.expiresFromNow = function (seconds, cbHandler) {
this._handle.ExpiresFromNow (seconds, cbHandler);
};
com.domain.util.timer.prototype.wait = function (seconds, cbHandler) {
this._handle.Wait (seconds, cbHandler);
};
com.domain.util.timer.prototype.expiresAt = function (seconds, cbHandler) {
this._handle.Wait (seconds, cbHandler);
};
com.domain.util.timer.prototype.cancel = function () {
this._handle.Cancel ();
};
Usage:
1. var timer = new com.domain.util.timer (); OK
timer.expiresAt (1, {}); OK
2. var func = $("timer"); OK
var timer = new func (); OK
timer.expiresAt (1, {}); OK
But but but but but
var timer = new $("timer") (); NG
Can anyone tell me why the last new function is not working?
Try var timer = new ($("timer"))();.
Your question is not clear but I guess since $("timer") returns a function, you want a new instance of the result of $("timer") and not a new instance of $().

how to call function using name such as "function someName(){}"?

I have a name of a private function in JavaScript as a string, how do I call that function?
var test = function () {
this.callFunction = function(index) {
return this["func" + index]();
}
function func1() { }
function func2() { }
...
function funcN() { }
}
var obj = new test();
obj.callFunction(1);
func1 and friends are local variables, not members of the object. You can't call them like that (at least not in any sane way).
Define them with function expressions (instead of function declarations) and store them in an array.
var test = function () {
this.callFunction = function(index) {
return funcs[index]();
}
var funcs = [
function () {},
function () {},
function () {}
];
}
var obj = new test();
obj.callFunction(0);
As your code stands, the functions are not present as properties of the instance. What you need to do is create them as properties of the context.
var test = function () {
this.callFunction = function(index) {
return this["func" + index];
}
this.func1 = function() { }
this.func2 = function() { }
...
}
var obj = new test();
obj.callFunction(1)();
you can use eval
var test = function () {
this.callFunction = function(index) {
return eval("func" + index + '()');
}
function func1() {
return 1;
}
function func2() {
return 2;
}
function funcN() { }
};
var obj = new test();
obj.callFunction(2);
eval is evil
You can use a private array of functions:
var test = function() {
var func = [
function() { return "one" },
function() { return "two"; }
]
this.callFunction = function(index) {
return func[index]();
}
}
var obj = new test();
var ret = obj.callFunction(1);
console.log(ret);​
​
http://jsfiddle.net/V8FaJ/

Categories

Resources