I have such JS class that have to be tested:
SomeClass = function {
// some stuff that uses initRequest
this.initRequest = function() {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else if (window.ActiveXObject) {
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
}
I want to override method initRequest for testing purposes. I tried to do something like that
var request = new MockXmlHttpRequest();
var instance = new SomeClass();
instance.initRequest = function() {
return request;
};
// some calls of the SomeClass methods that use initRequest
// some test code with assertions for the request
Still calling of the initRequest method calls actually the original code, but not the function that I tried to pass to instance.initRequest.
Any ideas what's wrong?
Check out YUI's extend functionality. It makes all this really clean, PLUS, you can still access the method of the super class if you really want to. Their augment object might also be of interest to you.
Here is the link http://developer.yahoo.com/yui/examples/yahoo/yahoo_extend.html
In your first example, initRequest returns a new object after each call; in the second example, all calls to initRequest return a reference to the one and only (mock) object.
The request object is not changed in the code example you provide. instance.initRequest simple returns a reference to request. Why do expect it to have changed?
I'm having a little trouble understanding your question because of your English, but I'll try to answer anyway (and if I answer the wrong question just let me know).
I think what you want to do is:
SomeClass = function {
// some stuff that uses initRequest
this.initRequest = function() {
return request;
}
}
In other words, you want to overwrite the original SomeClass object with a new function. Unless you do that new SomeClass objects won't use your test method, they'll just use the original method.
However, if you only want to override that method for a specific object, not for the whole class, what you have there should work. If that's the case, could you please clarify what exactly isn't working about it?
SomeClass.prototype.initRequest = function()
{
return request;
}
First of all, this code sample is not the best way of OOP in JavaScript - use prototype instead. Another remark, your sample throws error in my browser (invalid declarartion of SomeClass function, maybe it's only typing mistake). And at last, instance.initRequest actually returns (I've run it at Google Chrome) object you have expected - check please my sample.
Related
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
I have some code as part of a javascript weekend project that I'm working on. My problem is in the last line. As far as I can tell, I should be able to just call Floater.create() and not have to call Floater.prototype.create(). Why do I need the extra .prototype? Without it, an error is thrown: Floater() has no method "create"
function Floater(){}
Floater.prototype.create = function(){
//do stuff
}
$(document).ready(function(){
//do stuff
runStartup();
});
function runStartup(){
loginFloater = new Floater;
Floater.prototype.create();
// as far as I know, this should run as just Floater.create(),
// but that throws an error.
}
This part:
Floater.prototype.create = function(){
//do stuff
}
does not add a property to the Floater constructor, but to the [[Prototype]] object of instances created with new Floater(). So, Floater instances will have that method, but the constructor won't.
You may be looking to change your start-up function to:
function runStartup(){
loginFloater = new Floater();
loginFloater.create();
}
But, given the name of your method, you also may want to remove create altogether, and do initialization stuff directly from the constructor:
function Floater(){
// init stuff here
}
As an siginificantly simplified scenario, say I have 2 Javascript objects defined as below:
var ClassA = Class.extend({
'say': function(message) {
console.log(message);
}
... // some more methods ...
});
var ClassB = Class.extend({
init: function(obj) {
this._target = obj;
}
});
I'd suppose that in Javascript there is some kind of mechanism could enable us to do the following trick:
var b = new ClassB( new ClassA() );
b.say("hello");
I'd like to find a way to detect if there is a method called upon ClassB, and the method is not defined in ClassB, then I can automatically forward the method call to be upon ClassA, which is a member variable in ClassB.
In a realworld scenario, ClassA is an object implemented as brwoser plugin and inserted into the webpage using <object> tag. It's method is implemented in C++ code so there is no way I can tell its methods from its prototype and insert it to ClassB's prototype beforehand.
I'd like to use the technical to create a native Javascript object, with a narraw-ed version of ClassA's interface. Is there a way I can do this?
I don't think there is a quick cross-browser solution to this.
If you only need Firefox, then use __noSuchMethod__
See here: is-there-such-a-thing-as-a-catch-all-key-for-a-javascript-object
and here: javascript-getter-for-all-properties
Otherwise, I would try something like this:
var b = new ClassB( new ClassA() );
// functionToCall is a string containing the function name
function callOnB(functionToCall) {
if(typeof b[functionToCall] === function) {
b[functionToCall]();
} else {
b._target[functionToCall](); // otherwise, try calling on A
}
}
This is using the Square Bracket Notation where
b.say('hello')
is the same as
b['say']('hello')
Of course, you should probably expand this to take arguments in:
function callOnB(functionToCall, listOfArguments) {...}
Thanks to jfrej's hint on noSunchMethod, I did some more research on it and it turns out what I need is quit fit with Harmony Proxies(here and here). And an example can be found at http://jsbin.com/ucupe4/edit#source
Another related post: http://dailyjs.com/2010/03/12/nosuchmethod/
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 not a Javascript person normally, but I've been diving in, reading Douglas Crockford's book, and writing some trivial, useful tidbits as Chrome extensions and Node.js (note that this question isn't about either of them).
Right now, I'm trying to figure out how to retain a reference to an object that's initiating an AJAX request, that is: once I set the onload event handler (this is from inside a Chrome extension, so I'm using the base XMLHttpRequest object), is there any way that I can refer back to MyObject in the following example:
MyObject.prototype = {
PerformAction: function() {
this.Request = new XMLHttpRequest();
this.Request.open("GET", this.ConstructUrl(), true);
// From within ActionResultHandler, 'this' will always be the XMLHttpRequest
this.Request.onload = this.ActionResultHandler,
this.Request.send(null);
}
}
Doing this exactly is going to assign this to be the request object itself, and if I simply introduce a wrapper:
this.Request.onload = function() { ActionResultHandler() };
well, that just isn't going to do anything, because the ActionResultHandler is now out of scope. The reason I'm asking here is because I've only found trivial cases of caller manipulation (e.g. manipulating what this refers to from inside a function), but given that OO-ified Javascript and AJAX are literally everywhere, this has to have to be a known, simple issue, but my Google-fu is failing me here. In C#, events are invoked in the context of whoever attaches to them, not the object firing the event, so this doesn't come up on a daily basis. Perhaps there's a much better JS pattern that avoids this issue entirely?
It's not really clear to me which variable you want to hold a reference to. Here's how you would retain a reference to MyObject in your onload handler:
MyObject.prototype = {
PerformAction: function() {
var MyObjectRef = MyObject,
ActionResultHandler = this.ActionResultHandler;
this.Request = new XMLHttpRequest();
this.Request.open("GET", this.ConstructUrl(), true);
// From within ActionResultHandler, 'this' will always be the XMLHttpRequest
this.Request.onload = function () {
ActionResultHandler.apply(MyObjectRef, arguments);
};
this.Request.send(null);
}
}
Edited
Ok, I reread your question again and it seems that you want to execute ActionResultHandler in the context of MyObject, so I tweaked my code to do this.
Have you tried...
this.Request.onload = this.ActionResultHandler.apply(this);
I'm thinking that's what you're looking for (sorry if it's not). Using .apply(this) will point ActionResultHandler to Object.
Check out this article on binding while you're at it! It helped me out a lot.