Javascript: Dynamically add functions to object - javascript

I have a GeneralWrapper object that calls the statically-defined functions in the Library1 and Library2 objects.
The aim is that by calling GeneralWrapper.someFunc(), this will also call Library1.someFunc() and Library2.someFunc() without me having to explicitly create a function in GeneralWrapper called someFunc.
I attempt to implement this in the __preamble method below:
var GeneralWrapper = {
__modespopulated: false,
__validmodes: { // All 3 of these
spoonFunc: 1, // functions exist
knifeFunc: 1, // in Library1 and
forkFunc: 1 // Library2
},
__switchMode: function(funcname){
if (funcname in GeneralWrapper.__validmodes){
console.log("calling function", funcname)
GeneralWrapper.__preamble()
Library1[ funcname ](); // Call mode in Library1
Library2[ funcname ](); // Call mode in Library2
}
},
/* Attach valid modes to General Wrapper at runtime */
__preamble: function(){
if (!GeneralWrapper.__modespopulated)
{
for (var mode in GeneralWrapper.__validmodes)
{
GeneralWrapper[mode] = function(){
GeneralWrapper.__switchMode(mode)
};
}
GeneralWrapper.__modespopulated = true
}
GeneralWrapper.__otherprestuff();
},
__otherprestuff: function(){
// Stuff
},
funcThatAlwaysGetsCalled: function(){
GeneralWrapper.__switchMode("forkFunc");
}
}
var Library1 = {
forkFunc(){console.log("Lib1","fork")},
spoonFunc(){console.log("Lib1","spoon")},
knifeFunc(){console.log("Lib1","knife")}
}
var Library2 = {
forkFunc(){console.log("Lib2","FORK")},
spoonFunc(){console.log("Lib2","SPOON")},
knifeFunc(){console.log("Lib2","KNIFE")}
}
// Okay, let's initialise the object
GeneralWrapper.funcThatAlwaysGetsCalled();
For some reason calls to GeneralWrapper.spoonFunc() and GeneralWrapper.knifeFunc() always defer to the Fork output.
I imagine the problem stems from the anonymous function assignment on the GeneralWrapper[mode] = blah line where JS treats it as the same function each time, but I don't know how to get around this.
Please advise.

Solution:
Change this line:
for (var mode in GeneralWrapper.__validmodes)
into this:
for (let mode in GeneralWrapper.__validmodes)
Explanation:
what happens in your code (when binding functions in __preamble's loop) is that you create an anonymous function, which is totally fine. The problem is, your anon function has received the mode as a reference to local variable, so it's value is not automatically cloned but rather accessed at runtime. The main problem is that you've used var keyword, which means "hoisted variable" (it gets declared at the top of the function it was defined inside, even if it's somewhere in the middle of your function's code). In this scenario, you need a "block-scoped" variable, which will be bound to each loop iteration separately.
You can read more about variables hostings on MDN:
var at MDN
let at MDN
One thing you have to know - let was introduced in ES2015, so if you worry about backward compatibility with older browsers, you either have to use Function.prototype.bind or IIFE

One potential problem here is that you're creating functions inside a loop which can lead to some performance problems or unexpected behavior.
I'd replace:
for (var mode in GeneralWrapper.__validmodes)
{
GeneralWrapper[mode] = function(){
GeneralWrapper.__switchMode(mode)
};
}
with:
for (var mode in GeneralWrapper.__validmodes)
{
GeneralWrapper[mode] = GeneralWrapper.__switchMode.bind(this, mode);
}
Which should solve the problem at hand.

Related

Javascript this vs using same var name within itself

I am new to Javascript, can someone please help me understand if there is a fundamental difference between these 2 ways
First where I use this to call a function defined inside the var itself
var TxMmm={
name: {},
timeout: 2000,
testFunc1: function(){
console.log("testFunc1");
testFunc2();
this.testFunc3();
},
testFunc3: function(){
console.log("Test func3");
}
}
function testFunc2(){
console.log("This is func2 is outside var");
}
v/s Below where I use the var TxMmm to call function defined inside itself.
var TxMmm={
name: {},
timeout: 2000,
testFunc1: function(){
console.log("testFunc1");
testFunc2();
TxMmm.testFunc3();
},
testFunc3: function(){
console.log("Test func3");
}
}
function testFunc2(){
console.log("This is func2 is outside var");
}
In that specific code there isn't that much difference, because the object is a singleton. Some differences:
In your first code block using this, this could refer to something other than the TxMmm object in (say) testFunc1, depending on how testFunc1 is called. For instance, this would fail:
const fn = TxMmm.testFunc1;
fn();
But in your second code block, TxMmm will refer to the object (unless the next point comes into play), so that would work. More here and here.
If someone does:
const x = TxMmm;
TxMmm = somethingElse;
x.testFunc1();
...your first code block using this will keep working, because this is set by how testFunc1 is called. But your second code block using TxMmm would fail, because TxMmm doesn't point to the object anymore.
It almost never matters (seriously, very nearly never), but in your second code block, when you use TxMmm, the JavaScript engine has to look up that identifer to find it in the enclosing scope. Your code using this is able to resolve it immediately (since those aren't arrow functions), which in very rare situations can be faster in a noticeable way.
For non-singleton objects, this can be very important, since it tells the code which object's properties to use.

How can a property be assigned during object construction with a value generated asynchronously?

How can a property be assigned during object construction with a value generated asynchronously?
I'm trying to assign a property to an object during construction that needs to be retrieved via AJAX:
//define module prototype
Library.Module = function () {
this.resources = {};
for (var i = 0; i < arguments.length; i++) {
// assume that Library.require makes a request and
// then executes this callback
Library.require(arguments[i], function (resource) {
// ! the problem seems to be that 'this' is undefined
// in the scope of the callback
this.resources[resource.location] = resource;
});
}
};
I think the intention of this code is rather clear - The problem is that this appears to be undefined in the scope of the callback function.
As seen in the following article https://blog.engineyard.com/2015/mastering-this-in-javascript and following discussion in comments, a possible solution would be to store this in a variable higher in the scope to use it in the callback.
Therefore a possible solution could be :
Library.Module = function () {
var _this = this;
_this.resources = {};
for (var i = 0; i < arguments.length; i++) {
// assume that Library.require makes a request and
// then executes this callback
Library.require(arguments[i], function (resource) {
_this.resources[resource.location] = resource;
});
}
};
Useful snippet from the article cited:
Managing this in a callback
And that’s it: those are the four ways to set a function’s this value.
Those four rules are not too hard to remember, but there is a common
pitfall you should know about. I’m talking about callbacks. It’s easy
to be writing a callback and not even know it, like in setTimeout:
setTimeout(function() {
$(‘button’).addClass(‘red’);
}, 1000);
The setTimeout function accepts a callback, but since it’s not using
one of the four rules for setting context, this defaults to the global
window object. That’s fine in the example above, but becomes a bug in
code like this:
$('button').on('click', function() {
setTimeout(function() {
// Uh oh! `this` is the global object!
$(this).addClass('clicked');
}, 1000);
});
We’re expecting $(this) to refer to the button that was clicked, but
it doesn’t, since this defaults to the global window object. One way
to solve this issue is to store our desired value of this in a local
variable and then simply use that variable in a child scope:
$('button').on('click', function() {
var _this = this;
setTimeout(function() {
$(_this).addClass('clicked'); // All better
}, 1000);
});
Of course there are many ways to accomplish the same thing. You could
use .bind(), .call(), or a number of other options. Choose what works
best for each individual situation.

Javascript - Handle function calls dynamically [duplicate]

In Ruby I think you can call a method that hasn't been defined and yet capture the name of the method called and do processing of this method at runtime.
Can Javascript do the same kind of thing ?
method_missing does not fit well with JavaScript for the same reason it does not exist in Python: in both languages, methods are just attributes that happen to be functions; and objects often have public attributes that are not callable. Contrast with Ruby, where the public interface of an object is 100% methods.
What is needed in JavaScript is a hook to catch access to missing attributes, whether they are methods or not. Python has it: see the __getattr__ special method.
The __noSuchMethod__ proposal by Mozilla introduced yet another inconsistency in a language riddled with them.
The way forward for JavaScript is the Proxy mechanism (also in ECMAscript Harmony), which is closer to the Python protocol for customizing attribute access than to Ruby's method_missing.
The ruby feature that you are explaining is called "method_missing" http://rubylearning.com/satishtalim/ruby_method_missing.htm.
It's a brand new feature that is present only in some browsers like Firefox (in the spider monkey Javascript engine). In SpiderMonkey it's called "__noSuchMethod__" https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/NoSuchMethod
Please read this article from Yehuda Katz http://yehudakatz.com/2008/08/18/method_missing-in-javascript/ for more details about the upcoming implementation.
Not at the moment, no. There is a proposal for ECMAScript Harmony, called proxies, which implements a similar (actually, much more powerful) feature, but ECMAScript Harmony isn't out yet and probably won't be for a couple of years.
You can use the Proxy class.
var myObj = {
someAttr: 'foo'
};
var p = new Proxy(myObj, {
get: function (target, methodOrAttributeName) {
// target is the first argument passed into new Proxy, aka. target is myObj
// First give the target a chance to handle it
if (Object.keys(target).indexOf(methodOrAttributeName) !== -1) {
return target[methodOrAttributeName];
}
// If the target did not have the method/attribute return whatever we want
// Explicitly handle certain cases
if (methodOrAttributeName === 'specialPants') {
return 'trousers';
}
// return our generic method_missing function
return function () {
// Use the special "arguments" object to access a variable number arguments
return 'For show, myObj.someAttr="' + target.someAttr + '" and "'
+ methodOrAttributeName + '" called with: ['
+ Array.prototype.slice.call(arguments).join(',') + ']';
}
}
});
console.log(p.specialPants);
// outputs: trousers
console.log(p.unknownMethod('hi', 'bye', 'ok'));
// outputs:
// For show, myObj.someAttr="foo" and "unknownMethod" called with: [hi,bye,ok]
About
You would use p in place of myObj.
You should be careful with get because it intercepts all attribute requests of p. So, p.specialPants() would result in an error because specialPants returns a string and not a function.
What's really going on with unknownMethod is equivalent to the following:
var unk = p.unkownMethod;
unk('hi', 'bye', 'ok');
This works because functions are objects in javascript.
Bonus
If you know the number of arguments you expect, you can declare them as normal in the returned function.
eg:
...
get: function (target, name) {
return function(expectedArg1, expectedArg2) {
...
I've created a library for javascript that let you use method_missing in javascript: https://github.com/ramadis/unmiss
It uses ES6 Proxies to work. Here is an example using ES6 Class inheritance. However you can also use decorators to achieve the same results.
import { MethodMissingClass } from 'unmiss'
class Example extends MethodMissingClass {
methodMissing(name, ...args) {
console.log(`Method ${name} was called with arguments: ${args.join(' ')}`);
}
}
const instance = new Example;
instance.what('is', 'this');
> Method what was called with arguments: is this
No, there is no metaprogramming capability in javascript directly analogous to ruby's method_missing hook. The interpreter simply raises an Error which the calling code can catch but cannot be detected by the object being accessed. There are some answers here about defining functions at run time, but that's not the same thing. You can do lots of metaprogramming, changing specific instances of objects, defining functions, doing functional things like memoizing and decorators. But there's no dynamic metaprogramming of missing functions as there is in ruby or python.
I came to this question because I was looking for a way to fall through to another object if the method wasn't present on the first object. It's not quite as flexible as what your asking - for instance if a method is missing from both then it will fail.
I was thinking of doing this for a little library I've got that helps configure extjs objects in a way that also makes them more testable. I had seperate calls to actually get hold of the objects for interaction and thought this might be a nice way of sticking those calls together by effectively returning an augmented type
I can think of two ways of doing this:
Prototypes
You can do this using prototypes - as stuff falls through to the prototype if it isn't on the actual object. It seems like this wouldn't work if the set of functions you want drop through to use the this keyword - obviously your object wont know or care about stuff that the other one knows about.
If its all your own code and you aren't using this and constructors ... which is a good idea for lots of reasons then you can do it like this:
var makeHorse = function () {
var neigh = "neigh";
return {
doTheNoise: function () {
return neigh + " is all im saying"
},
setNeigh: function (newNoise) {
neigh = newNoise;
}
}
};
var createSomething = function (fallThrough) {
var constructor = function () {};
constructor.prototype = fallThrough;
var instance = new constructor();
instance.someMethod = function () {
console.log("aaaaa");
};
instance.callTheOther = function () {
var theNoise = instance.doTheNoise();
console.log(theNoise);
};
return instance;
};
var firstHorse = makeHorse();
var secondHorse = makeHorse();
secondHorse.setNeigh("mooo");
var firstWrapper = createSomething(firstHorse);
var secondWrapper = createSomething(secondHorse);
var nothingWrapper = createSomething();
firstWrapper.someMethod();
firstWrapper.callTheOther();
console.log(firstWrapper.doTheNoise());
secondWrapper.someMethod();
secondWrapper.callTheOther();
console.log(secondWrapper.doTheNoise());
nothingWrapper.someMethod();
//this call fails as we dont have this method on the fall through object (which is undefined)
console.log(nothingWrapper.doTheNoise());
This doesn't work for my use case as the extjs guys have not only mistakenly used 'this' they've also built a whole crazy classical inheritance type system on the principal of using prototypes and 'this'.
This is actually the first time I've used prototypes/constructors and I was slightly baffled that you can't just set the prototype - you also have to use a constructor. There is a magic field in objects (at least in firefox) call __proto which is basically the real prototype. it seems the actual prototype field is only used at construction time... how confusing!
Copying methods
This method is probably more expensive but seems more elegant to me and will also work on code that is using this (eg so you can use it to wrap library objects). It will also work on stuff written using the functional/closure style aswell - I've just illustrated it with this/constructors to show it works with stuff like that.
Here's the mods:
//this is now a constructor
var MakeHorse = function () {
this.neigh = "neigh";
};
MakeHorse.prototype.doTheNoise = function () {
return this.neigh + " is all im saying"
};
MakeHorse.prototype.setNeigh = function (newNoise) {
this.neigh = newNoise;
};
var createSomething = function (fallThrough) {
var instance = {
someMethod : function () {
console.log("aaaaa");
},
callTheOther : function () {
//note this has had to change to directly call the fallThrough object
var theNoise = fallThrough.doTheNoise();
console.log(theNoise);
}
};
//copy stuff over but not if it already exists
for (var propertyName in fallThrough)
if (!instance.hasOwnProperty(propertyName))
instance[propertyName] = fallThrough[propertyName];
return instance;
};
var firstHorse = new MakeHorse();
var secondHorse = new MakeHorse();
secondHorse.setNeigh("mooo");
var firstWrapper = createSomething(firstHorse);
var secondWrapper = createSomething(secondHorse);
var nothingWrapper = createSomething();
firstWrapper.someMethod();
firstWrapper.callTheOther();
console.log(firstWrapper.doTheNoise());
secondWrapper.someMethod();
secondWrapper.callTheOther();
console.log(secondWrapper.doTheNoise());
nothingWrapper.someMethod();
//this call fails as we dont have this method on the fall through object (which is undefined)
console.log(nothingWrapper.doTheNoise());
I was actually anticipating having to use bind in there somewhere but it appears not to be necessary.
Not to my knowledge, but you can simulate it by initializing the function to null at first and then replacing the implementation later.
var foo = null;
var bar = function() { alert(foo()); } // Appear to use foo before definition
// ...
foo = function() { return "ABC"; } /* Define the function */
bar(); /* Alert box pops up with "ABC" */
This trick is similar to a C# trick for implementing recursive lambdas, as described here.
The only downside is that if you do use foo before it's defined, you'll get an error for trying to call null as though it were a function, rather than a more descriptive error message. But you would expect to get some error message for using a function before it's defined.

Newbie: Javascript constructor and scope-context issue

I'm confused as to what the problem is with context in a JS constructor. Within the ctor I have a function declared. Before the call to that function this is set to the context of the ctor. Inside the function the value of this is set to window. I don't understand why. In the HTML the ctor is called with 'new'.
function MyCtor() {
var myFunc = function() {
debugger; // #2
// code for myFunc
}
debugger; // #1
myFunc();
debugger; // #3
}
At debugger #1, this is set to MyCtor. At #2 this is window. And at #3 it is back to MyCtor.
I'm sure I'm missing something basic here, but I've read a lot on scope and context; obviously not enough.
The this object is one of the most annoyingly hard-to-understand concepts in Javascript. And that's quite a contest to win... First off, you have to understand that it will be specific to each function you call - the context in which you call myFunc won't set it how you want it. Here's one way you can do it:
function MyCtor() {
this.myFunc = function() {
debugger; // #2
// code for myFunc
}
debugger; // #1
this.myFunc();
debugger; // #3
}
Generally, there are only a few situations in which you can rely upon a function's this to be a particular value. All of them to my knowledge:
objectToBeThis.aFunction = function() { ... } // declare this function as
// an object property at any time -
objectToBeThis.aFunction();
Or, not used as often is:
aFunction.call(objectToBeThis, extraArgument1, extraArgument2);
When a named, but not "owned" function (ie, var functionName = function(), or function functionName()) is called, then it will have window as its this argument. This part I'm less sure of as a certainty, but I just wouldn't use this inside such a method.
As in the case of your code, there's also "new MyCtor" - in which a new object is created to be returned, and that object is set to this inside of the constructor method.

Access to public and private methods from event handler closure

I have a difficulty in understanding, how my current JavaScript code works. I've managed to solve a problem in accessing private object method from event handler closure, but I'd like to know why does it work so.
The code utilizes the well-known module/plugin metaphor:
(function(module, $, undefined)
{
function myPrivateCode(e){ /*...*/ }
module.myPublicCode = function(e) { /*...*/ }
module.init = function()
{
var that = this;
$('.clickable').click(function(e)
{
if($(e.target).hasClass('classX'))
{
that.myPublicCode(e.target); // requires 'that' to work
}
else
{
// that.
myPrivateCode(e.target); // will fail if 'that' uncommented
}
});
}
}(window.module = window.module || {}, jQuery ));
In the code I set a click handler which invokes either public or private method. It's perfectly conceivable that we need to pass an object reference into the event handler closure, which is done by that local variable. What is strange to me is that myPrivateCode does neither require that as a refernce, nor fails due to its "privacy". This makes me think that myPrivateCode accesses not the appropriate object, and works somehow differently to expected way. Could someone explain what happens? Certainly I'm missing something.
Both that and myPrivateCode are available to your event handler through a closure. In short, what's going on is that every variable and function you declare inside of another function has access to the outer scope.
myPublicCode, on the other hand, is not available through closures, because it's being assigned to your module object specifically. So the only way to call it is by using module.myPublicCode() (or that.myPublicCode() as you did – but you don't actually need that there, since module is also available).
Your call to myPrivateCode(e.target); is running in the context of the anonymous function that you pass as a handler to the click function.
For more information, read up on closures.
For a simpler example, try out this code:
var foo = function () {
var a = 1;
return function (b) {
return a+b;
}
};
var bar = foo();
bar(1); // 2
bar(1) will always always gives 2, because a = 1 was in scope when the function was created. In your case, a is your that and your handler is the closed function.
http://jsfiddle.net/Fh8d3/

Categories

Resources