I just want to confirm that I'm not missing something with regards to managing context and overriding methods. I'm using the http-proxy module in a node.js app and I need to override the function HttpProxy.prototype.proxyRequest. I'd like to do it without modifying the original module code directly but haven't been able to find a way to do it.
If I do this:
var httpProxy = require('http-proxy'),
httpProxyOverride = require('./http-proxy-override.js');
httpProxy.HttpProxy.prototype.proxyRequest = httpProxyOverride.proxyRequestOverride;
Then I lose the original context and errors are thrown. If I use apply(), I can provide a new context, but it doesn't appear I can persist the original context.
Based off of this SO thread:
Is it possible to call function.apply without changing the context?
It doesn't appear that there is a way to achieve what I'm trying to do and I'm hoping that someone can confirm this or correct me if I'm wrong.
What about saving the old function and then overwriting it like:
var old = httpProxy.HttpProxy.prototype.proxyRequest;
httpProxy.HttpProxy.prototype.proxyRequest = function () {
old.apply(this, arguments);
//do more stuff
}
taken from Javascript: Extend a Function
Related
I'm searching for alternative ways to call a method defined in Marionette's behaviors from inside a view.
For sure there is the eventproxy but maybe it's more intuitive to call the method directly like:
view.behaviorsMethod();
I could assign it like:
view.method = behavior.method;
I could check for reassignment because it'll maybe lead to unexpected results for others:
view.method = (view.method !== undefined ? view.method : behavior.method);
But this doesn't seem to be an elegant way.
The answer to your question is you can not directly do so, but there is always a way.
you can do it using _.invoke(this._behaviors, 'yourMethodName') but I will discourage using it
since
_behaviors is a private variable of the Marionette.View class and it's name can be changed or it can be dropped in upcoming versions
You will have to set context for the method as _.invoke will not set
the context of the method to proper this.
if you can set the context properly then this will work for you.
as suggested by #ThePaxBisonica in comment
I will suggest you to go with a mixin pattern from which you can extend both your behavior and view and you will not have to set any context and do not have to worry about the _behavior private variable
as
var mixin = {
behaviorMethodWhichYouWantToCallFromView: function(){
alert("mixin method");
}
}
var behavior = mn.behavior.extend(_.extend(mixin, {
//actual behavior code remove the method as behavior will get it from mixin
}))
var view = mn.view.extend(_.extend(mixin, {
//actual view code remove the method as behavior will get it from mixin
}))
Hope it helps.
I know this is bit long approach.
I've peeked into many plugins' code (for educational purposes) and basically every one of them (which deals with prototypes), has bunch of functions like this:
myMarker.prototype.getPosition = function() {
return this.latlng;
};
//OR
myMarker.prototype.getObject = function() {
return this;
};
What's the reason behind this?
Why not just to use someObject.latlng instead of someObject.getPosition()?
One common reason for doing this is to avoid coupling the object's internal data storage to the API; in this example you could change the way the position is stored internally, and then add some processing to getPosition() to return a backwards compatible result.
For example, version 1.1 of this library might look like this, and calling code wouldn't need to be changed:
myMarker.prototype.getPosition = function() {
return this.latitude + this.longitude;
};
It is possible to accomplish this using computed properties with ES5 get and set, but only if the code doesn't need to run on Internet Explorer 8 and below.
When you say like this.
myMarker.prototype.getPosition = function() {
return this.latlng;
};
You are defining function getPosition which available to all instance to class myMarker.
So,all object of this class share this method without replication.
For someObject.latlng,there is nothing wrong.
But assume, this object is accessible to all which are in the current scope.So,it can be modified/accessible to anyone.
When you go through prototype you are trying to define some pattern,which gives restriction for access and modification of property
As of Firefox 36, Function.__exposedProps__ was made unavailable. Instead if one wanted to expose a chrome JS object to be used in content scripts, they have to use Components.utils.cloneInto with the target scope as browser.contentWindow.wrappedJSObject.
If one does not turn on the cloneFunctions flag, only those attributes are cloned that are not functions. Turning the flag does clone functions too, but not those functions that are defined via the Function.prototype path. For those functions one has to export them via Components.utils.exportTo with the target scope as your exposed object.
Coming to the issue I'm facing. (As I am unable to put it in words, I am adding a MWE).
Chrome end JS:
function Foo(){
this._nFunc = "something";
this._func = function(){/*do something*/};
}
Foo.prototype.Bar = function(){
this._func();
}
Foo.prototype.FooBar = function(){
this._nFunc = "somthing else";
}
var myFoo = new Foo();
var targetScope = browser.contentWindow.wrappedJSObject;
targetScope.myExposedObject = Components.utils.cloneInto(myFoo, targetScope, {cloneFunctions:true});
Components.utils.exportFunction(myFoo.Bar, targetScope.myExposedObject , {defineAs:"Bar"});
Components.utils.exportFunction(myFoo.FooBar, targetScope.myExposedObject , {defineAs:"FooBar"});
Content end JS:
window.myExposedObject.FooBar(); // works
window.myExposedObject._func(); // works
window.myExposedObject.Bar() // error this._func is undefined
Upon logging the this scope received by the function Bar(), we get _func:(void 0), while _nFunc is logged correctly.
Questions:
Is there something I'm missing, or is this a limitation in Firefox? If it is a limitation, please suggest possible ways to workaround the limitation.
Initially I thought that Bar() was somehow unable to access the scope of the calling object, and I tried to supply it the scope as parameters, i.e., Foo.prototype.Bar = function(scope){ scope._func();} and window.myExposedObject.Bar(window.myExposedObject);. Interestingly upon logging, the scope object also turned out to be (void 0). Why is that? I am sure that I am missing something here. What I expected was that the exposed object would map to the original object and upon sending the exposed object as parameters the chrome end JS would be able to get the original object.
While what you're trying to do might be possible with the right combination of cloneInto/exportFunction and waiving of xrays i would suggest you simply load the unprivileged part of your class hierarchy directly into the target context with the subscript loader and only hook the minimal amount of privileged functions into the prototype once it has been created.
This should reduce the attack surface and also avoid headaches with inheritance.
Additionally, these may prove useful:
https://developer.mozilla.org/en-US/docs/Components.utils.createObjectIn
https://developer.mozilla.org/en-US/docs/Components.utils.makeObjectPropsNormal
I am using an open source javascript library timeline.verite.co
It's a timeline library which works great on page load. But when I try to repaint the timeline on certain condition, it starts giving out weird errors
I would like to modify the init function in the library. But instead of changing it in the original library itself, I would like to rewrite/override this function in another separate .js file so that when this function is called, instead of going to the original function, it must use my modified function.
I'm not sure whether to use prototype/ inheritance and how to use it to solve this problem?
You only need to assign the new value for it. Here is an example:
obj = {
myFunction : function() {
alert('originalValue');
}
}
obj.myFunction();
obj.myFunction = function() {
alert('newValue');
}
obj.myFunction();
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