I am trying to write a javascript class that loads script files as they are needed. I have most of this working. It is possible to use the library with the following Syntax:
var scriptResource = new ScriptResource('location/of/my/script.js');
scriptResource.call('methodName', arg1, arg2);
I would like to add some additional syntactic sugar so you could write
var scriptResource = new ScriptResource('location/of/my/script.js');
scriptResource.methodName(arg1, arg2);
I'm almost certain that this isnt possible but there may be an inventive solution. I guess what there need to be is some sort of methodCall event. SO the following could work
ScriptResource = function(scriptLocation)
{
this.onMethodCall = function(methodName)
{
this.call(arguments);
}
}
This code is obviously very incomplete but I hope it gives an idea of what I am trying to do
Is something like this even remotely possible?
There is a non standard method, __noSuchMethod__ in Firefox that does what you're looking for
have a look at
https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Object/noSuchMethod
so you could define
obj.__noSuchMethod__ = function( id, args ) {
this[id].apply( this, args );
}
If the set of method names is limited, then you could generate those methods:
var methods = ["foo", "bar", "baz"];
for (var i=0; i<methods.length; i++) {
var method_name = methods[i];
WildCardMethodHandler[method_name] = function () {
this.handleAllMethods(method_name);
};
}
edit: Posted this answer before the question changed dramatically.
An intermediary solution might be to have syntax such as:
var extObj = ScriptResource('location/of/my/script.js');
extObj('methodname')(arg1,arg2);
the code might look like this:
function ScriptResource(file) {
return function(method) {
loadExternalScript(file);
return window[method];
}
}
All kinds of assumptions in the code above, which I'd let you figure out yourself. The most interesting, IMHO, is - in your original implementation - how do you get the proxyied method to run synchronously and return a value? AFAIK you can only load external scripts asynchronously and handle them with an "onload" callback.
Related
So, I have a lot of places with code, when I push some elements to array:
arr.push(...)
But the problem is, that I would like to run custom code after each push. Basically the question is not only about this example. What I want to do is something like this:
func1.func2(...);
After this I want to run another function which will get all things, which func2 did and for example log it. But these functions in code are a lot and it is not desirable to write something like this every time:
if (func1.func2(...)) {
log_results();
}
Instead, for every func1.func2() I want automatically run another separate function, which will get results and log it.
The only way to really accomplish this is to wrap it in a function that does the extra work you want.
function pushAndLog(item) {
arr.push(item);
// Additional Code here
logResults();
}
This is an interesting question. There are plenty of libraries like Lodash that do similar things to functions. Like methods that return copies of functions with arguments partially applied: _.curry. I tested it and it works on Array.prototype.push.
Doing some research I found this post with this answer: JavaScript: clone a function and decided to try to do what you wanted without making the clone method.
Here is what I came up with. Replace the console.log with a call to any function you like or any other code you wish.
Array.prototype.push = (function() {
var old = Array.prototype.push;
var push = function () {
console.log('my new push where I can do what I want, like log some stuff');
return old.apply(this, arguments)
};
return push;
})();
var foo = [];
foo.push(1,2,3);
console.log(foo);
You could add another prototype to Array that uses push inside and then whatever else you want to execute.
let testArr = [];
Array.prototype.pushPlusStuff = function(val) {
this.push(val);
console.log("executing other stuff here");
};
testArr.pushPlusStuff("test");
console.log(testArr);
This will make the .pushPlusStuff method available to all Arrays
Actually gforce301 code helped me. I was dealing with Google dataLayer and the task was to log all push data (except some). This code snippet helped me:
var dataLayer_copy = dataLayer.push;
dataLayer.push = function() {
dataLayer_copy.apply(this, arguments);
console.log(JSON.stringify(arguments));
$.post('/log', {data: arguments}, function() {
}, 'json');
};
I've got a browser addon I've been maintaining for 5 years, and I'd like to share some common code between the Firefox and Chrome versions.
I decided to go with the Javascript Module Pattern, and I'm running into a problem with, for example, loading browser-specific preferences, saving data, and other browser-dependent stuff.
What I'd like to do is have the shared code reference virtual, overrideable methods that could be implemented in the derived, browser-specific submodules.
Here's a quick example of what I've got so far, that I've tried in the Firebug console, using the Tight Augmentation method from the article I referenced:
var core = (function(core)
{
// PRIVATE METHODS
var over = function(){ return "core"; };
var foo = function() {
console.log(over());
};
// PUBLIC METHODS
core.over = over;
core.foo = foo;
return core;
}(core = core || {}));
var ff_specific = (function(base)
{
var old_over = base.over;
base.over = function() { return "ff_specific"; };
return base;
}(core));
core.foo();
ff_specific.foo();
Unfortunately, both calls to foo() seem to print "core", so I think I've got a fundamental misunderstanding of something.
Essentially, I'm wanting to be able to call:
get_preference(key)
set_preference(key, value)
load_data(key)
save_data(key, value)
and have each browser do their own thing. Is this possible? Is there a better way to do it?
In javascript functions have "lexical scope". This means that functions create their environment - scope when they are defined, not when they are executed. That's why you can't substitute "over" function later:
var over = function(){ return "core"; };
var foo = function() {
console.log(over());
};
//this closure over "over" function cannot be changed later
Furthermore you are "saying" that "over" should be private method of "core" and "ff_specific" should somehow extend "core" and change it (in this case the private method which is not intended to be overridden by design)
you never override your call to foo in the ff_specific code, and it refers directly to the private function over() (which never gets overridden), not to the function core.over() (which does).
The way to solve it based on your use case is to change the call to over() to be a call to core.over().
That said, you're really confusing yourself by reusing the names of things so much, imo. Maybe that's just for the example code. I'm also not convinced that you need to pass in core to the base function (just to the children).
Thanks for your help. I'd forgotten I couldn't reassign closures after they were defined. I did figure out a solution.
Part of the problem was just blindly following the example code from the article, which meant that the anonymous function to build the module was being called immediately (the reusing of names Paul mentioned). Not being able to reassign closures, even ones that I specifically made public, meant I couldn't even later pass it an object that would have its own methods, then check for them.
Here's what I wound up doing, and appears to work very well:
var ff_prefs = (function(ff_prefs)
{
ff_prefs.foo = function() { return "ff_prefs browser specific"; };
return ff_prefs;
}({}));
var chrome_prefs = (function(chrome_prefs)
{
chrome_prefs.foo = function() { return "chrome_prefs browser specific"; };
return chrome_prefs;
}({}));
var test_module = function(extern)
{
var test_module = {};
var talk = function() {
if(extern.foo)
{
console.log(extern.foo());
}
else
{
console.log("No external function!");
}
};
test_module.talk = talk;
return test_module;
};
var test_module_ff = new test_module(ff_prefs);
var test_module_chrome = new test_module(chrome_prefs);
var test_module_none = new test_module({});
test_module_ff.talk();
test_module_chrome.talk();
test_module_none.talk();
Before, it was running itself, then when the extension started, it would call an init() function, which it can still do. It's just no longer an anonymous function.
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.
I'm building a Javascript/AJAX heavy web application using jQuery and I'm looking for a way to map URLs/Routes to Javascript functions. I'm using the HTML5 history API and some rewrite rules so all requests will go to one HTML file but idealy what I'd like to do is something along the lines of
Routes.add('/some/path/', 'func_somepath');
Routes.add('/someother/path/', 'func_someotherpath');
function func_somepath(){
alert("You're at somepath");
}
function func_someotherpath(){
alert("You're at someotherpath");
}
Then when someone visited example.com/some/path/ the function 'func_somepath' would be called, similar with /someother/path/. It would also be nice to be able to use Rails-style or regexp variables in the URLs
Routes.add('/items/([a-z]+)', 'func_items');
func_items(id){
alert('You requested '+id+'!');
}
Does anything like this already exist or would I have to write it myself? I don't mind writing it myself but if something already exists there's no point. I'd also like to avoid using 'exec' so how would I go about calling the named functions in Routes.add?
Have you checked out Sinatra's JavaScript counter-part, SammyJS? ...*ba-dum-tish*
Don't use eval unless you absolutely, positively have no other choice.
As has been mentioned, using something like this would be the best way to do it:
window["functionName"](arguments);
That, however, will not work with a namespace'd function:
window["My.Namespace.functionName"](arguments); // fail
This is how you would do that:
window["My"]["Namespace"]["functionName"](arguments); // succeeds
In order to make that easier and provide some flexibility, here is a convenience function:
function executeFunctionByName(functionName, context /*, args */) {
var args = Array.prototype.slice.call(arguments).splice(2);
var namespaces = functionName.split(".");
var func = namespaces.pop();
for(var i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
return context[func].apply(this, args);
}
You would call it like so:
executeFunctionByName("My.Namespace.functionName", window, arguments);
Note, you can pass in whatever context you want, so this would do the same as above:
executeFunctionByName("Namespace.functionName", My, arguments);
Hope that helps...
Ember.js, senchatouch2, extjs4 are examples of a framework, that would let you do that easily
There are several functions in jquery which you can do the following:
$('#element').each().get('title').othercmd()
How can I create a class ( or a series of classes ) to replicate this behavior?
Basically, I want to something like this:
test = new Something()
test.generateSection('title').addData('somedata')
What is correct for this?
Thanks
One approach is to return "this" (the object) in each function. So you could do something like this:
<script>
var Something = function() {
this.hi = function() {
alert('hi');
return this;
};
this.bye = function() {
alert('bye');
return this;
};
}
var myObj = new Something();
myObj.hi().bye();
</script>
Just return the thing that you are operating on at the end of each method. (this usually).
You can implement a chain pattern just by returning the current instance in all the methods that you want to be able to chain.
Something.prototype.generateSection = function(title){
... code ...
this.sectionAdded = ...;
return this;
}
Something.prototype.addData = function(data)
{
... continue manipulating this.sectionAdded however you need it ..
return this;
}
And do the same with the other methods of your "class". Something to keep in mind is that you must store the objects that you will need in future calls, in your case you are generating a section, so you would have to put that inside your instance (in some private variable like sectionAdded) so you will be able to continue manipulating it from other methods.
I don't know if there is a way to easily chain together commands with plain javascript, but if you wanna try this with jQuery, you'll have to write your code as a jQuery plugin.
It's actually pretty easy and there are tons of tutorials for writing your own plugins.
One of the easiest I came across is this tutorial:
building-your-first-jquery-plugin-that.html