javascript: call method on dynamically generated object name - javascript

How would one call a method on a dynamically generated name? This is a case where I am passing the object name into a function and calling a method on that object. Something like this, where type is the name of the object I want to execute the method on:
function doSomething(type) {
type.someMethod();
}
Note that I do not want to pass the object into the function.

First, it is not clear what object that "type" belongs to. I'm guessing this is in scope, maybe something like this:
var typeObjects = {
type1: {
doSomething: function(){..},
..
},
type2: {
doSomething: function(){..},
..
},
..
}
Then, your function becomes the following:
function doSomething(typeName) {
typeObjects[typeName].someMethod();
}
And then you would call it like so:
doSomething('type1');

If your object is global, you could do this :
var global = global || window;
function doSomething(type) {
global[type].someMethod();
}
var myObject = {
someMethod : function () { console.log("calling someMethod") },
};
doSomething("myObject");

If you want to pass a variable name to a function, consider instead passing a property name of a predetermined object, so that your function is not unsafely accessing arbitrary objects from its scope with eval(), which is a bad practice for both security and performance reasons.
var myObject = {
foo: { someMethod () { console.log('fooObj') } },
bar: { someMethod () { console.log('barObj') } }
}
function doSomething (property) {
if (myObject.hasOwnProperty(property)) {
myObject[property].someMethod()
}
}
doSomething('foo')
doSomething('bar')
doSomething('nil') // does nothing

You need to eval the object name or method.
eval(type)['someMethod']();
or
eval(type + '.someMethod()');
Also if your object is at window scope, you can do
window[type].someMethod();

Related

Is it possible to append a method to a constructor/function without prototype property?

function DoIHavePrototype()
{
var a = 10;
}
CheckIt = new DoIHavePrototype();
DoIHavePrototype.prototype.GetFnName = function()
{
return "DoIHavePrototype"
}
alert(CheckIt.GetFnName())
In the above code,I observe that prototype is an in-built property for the function using which we can append property/method to a function.
But if I remove the prototype keyword in the above code like the following:
DoIHavePrototype.GetFnName = function()
{
return "DoIHavePrototype"
}
I don't get error in function definition but instead I get error while calling the method
alert(CheckIt.GetFnName()) as "CheckIt.GetFnName is not a function"
What does the JS interpreter assume this to be??
In order to be able to invoke some function a method on an object, there are 4 ways to introduce it to the object.
The first way is what you've done in your original code, which is to assign the function to the object prototype:
Foo.prototype.myFunc = function () { .... }
Another way is to assign it to this within the constructor.
function Foo() {
this.myFunc = function () { .... }
}
We can also assign it directly to the instance:
var foo = new Foo();
var myFunc = function () { .... }
foo.myFunc = myFunc
Finally, we can bind a function to the instance:
var foo = new Foo();
var myFunc = function () { .... }
var myFuncFoo = myFunc.bind(foo)
The last case is a bit special since we have a function that's not a property of the instance, but behaves like an instance method because it's invocation context is affixed to the instance.
The most common way of defining instance methods is assignment to the prototype. The prototype property on the constructor is what the instances inherit from, so that's where we put stuff. It's important to keep in mind that the instances inherit from the prototype property, not the constructor function. Assigning anything to a constructor property does not make it available as an instance property.
Assignment to this can sometimes be used if we want to have a method that's bound. For instance:
function Foo() {
this.boundMeth = this.meth.bind(this)
this.val = "foo"
}
Foo.prototype.meth = function () {
console.log(this.val)
}
This is useful if we want to pass instance.boundMeth() as a value to another function (e.g., event handler). In JavaScript, unlike many OO languages, methods are unbound:
// Using Foo from the previous example
function runner(fn) {
fn()
}
var obj = new Foo()
runner(obj.meth) // Logs `undefined`
runner(obj.boundMeth) // Logs `foo`
When assigning to the constructor prototype, you can assign in bulk:
Foo.prototype = {
meth1: function () { .... },
meth2: function () { .... },
}
If you use ES6, you can also use the class keyword:
class Foo {
myFunc() { .... }
}
This is the same as Foo.prototype.myFunc = function () { .... }.
If you append your function straight to the class it will generate so called static method which you can only call from you class like in Array.from.
So in your case you should call it using you class (not its instances) like so DoIHavePrototype.GetFnName();
you can read about this on MDN
This can also be done, in case if you still want to use it as instance method.
function DoIHavePrototype()
{
var a = 10;
this.GetFnName = function() {
return "DoIHavePrototype";
}
}
CheckIt = new DoIHavePrototype();
alert(CheckIt.GetFnName())

Get Object Method Name From Within That Same Method

Let's say I have an obj:
var app = {}
and a method inside the object
app = {
init: function () {
}
}
how would I go about obtaining the method name 'init' inside of init() without specifically looking for 'init'. This would be in the case that the method name could be anything and I can't rely on searching for a specific name.
app = {
init: function () {
//get 'init' method name here
}
}
app.init();
I tried using callee but that brings back an empty string
You could use a named function expression:
app = {
init: function init() {
console.log(arguments.callee.name);
}
};
app.init(); // => "init"
Note that use of arguments.callee is forbidden in strict mode.
What you are doing in your example is assigning an anonymous function expression to the property named init on your object. The function itself does not have a name unless you use a named function expression.

Javascript nested function losing scope

Can someone explains the scope binding of the following code please
window.name = "window";
object = {
name: "object",
method: function() {
nestedMethod: function() {
console.log(this.name);
}
nestedMethod();
}
}
object.method(); // print 'window'
I think my question is more about this...why is this losing the scope and default to the global scope ? do all the anonymous functions that we created will go on the global scope ?
Whenever you call a function, simply by writing func(), this inside the function will point to the global object. In your case you write:
nestedMethod();
So this inside nestedMethod is the window object. You can use call (or apply) to manually define a context for you function call:
nestedMethod.call(this);
Any function that's invoked like this:
someFunction();
will have the global scope as the value of this (in non-strict mode). You can either stash the outer scope in a local variable, or else use .call() or .apply():
nestedMethod.call(this);
window.name = "window";
object = {
name: "object",
method: function () {
var self = this;
var nestedMethod = function () {
console.log(self.name); // or object.name without declaring self
}
nestedMethod();
}
}
object.method(); // print 'object'
Save the scope of the object - or use the object itself!
do all the anonymous functions that we created will go on the global scope ?
No, not all the anonymous functions lose their scope, all the functions scopes are bound to the global object(if they are not called with specific this, see apply and call, see the example below)!
window.name = "window";
object = {
name: "object",
method: function () {
var nestedMethod = function () {
console.log(this.name);
}
nestedMethod.call(this); //change the this arg in the current object scope
// when you call this function with .call(this) you are changing the value of the nestedMethod's this to the current this, which is object
}
}
object.method(); // print 'object'
you should declare nested function like this:
Super.prototype.someFunc = function() {
this.nestedFunc = function() {}
//now call it
this.nestedFunc()
}

Javascript accessing functions of same class

In the following code:
function xyz(x) {
//something
this.x = x;
}
xyz.prototype = {
a: function () {
//do something
},
b: function () {
//pre
this.a();
//post
}
}
the call of this.a() gives the warning of method not supported. So I tried using xyz.prototype.a.call(this) instead. But it does not maintain the value of x. What do I do to call one method of a class from other?
Given your code, if you write:
var myXyz = new xyz("hello");
then calling
myXyz.b();
should correctly get to the "a()" function on the prototype. However, if you do something like this:
var otherB = myXyz.b;
otherB();
then it will not work, because there's no context object (that is, the this value inside "b()" won't be set correctly to an instance of "xyz"). That often happens when a function is being used as an event handler:
something.onclick = myXyz.b;
The event handler, when called, won't have an "xyz" instance to work with. Instead of that, therefore, you could write:
something.onclick = function() { myXyz.b(); };
which clearly ensures that there's an "xyz" object.

Javascript Nested Functions Scope

I have the following javascript object, somewhat pseudocode:
{
dateField: new Date(),
addMinutes:function(numMinutes)
{
CallWebService(numMinutes, function{alert(this.dateField; });
}
}
The problem is the scope of the callback function in CallWebService doesn't see the dateField property of the object. Is there a way I can access it? Thanks!
You need to preserve the context (the this value) of the addMinutes function.
There are several ways to achieve it, the most easy one is to simply store a reference of this on a variable, that variable will be available to the scope of the callback function, e.g.:
var obj = {
dateField: new Date(),
addMinutes: function(numMinutes) {
var instance = this;
CallWebService(numMinutes, function () {
alert(instance.dateField);
});
}
};
The issue is that the callback is likely setting the scope of the callback function, if you use apply or call you can force the scope. You can do this with something like this:
{
dateField: new Date(),
addMinutes: function (numMinutes) {
var self = this;
var success = function () {
alert(this.dateField;);
};
CallWebService(numMinutes, function () { success.apply(self); });
}
}
You can access any property(i.e variable or function) of an object inside that object scope by using the dot(.) operator. So you can use like this:
var obj = {
dateField: new Date(),
addMinutes: function(numMinutes) {
callWebService(numMinutes, function() {
alert(obj.dateField);
});
}
}
Here 'dateField' variable of the object 'obj' is accessible inside that object scope using the dot operator like 'obj.dateField'. I think this will help you to solve your problem, let me know if you are not clear with the code shown above.

Categories