Calling a default method in Js Object - javascript

Is there any way to create an object that respond to any message? Suppose you have the following object:
function Dog();
Dog.prototype.speak(){
alert("woof woof");
}
var myDog = new Dog();
Then when you do myDog.speak() you will get an alert with "Woof woof". But what I want is when you call myDog.jump() (which is not defined in the class) you will get a default action like show the user an alert with "you are trying to excecute an inexistent method".
Do you know how can I do it?

Short answer: you can't.
Long answer: you could use __noSuchMethod__ but it's not standard and there are some plans to remove it, because Proxy can do the same, and more. Plus, it's a standard.
Therefore, you could use a Proxy to do that, but I would discourage to have all objects as proxies, because performance reasons.
Personally, I would just leave the language thrown it's own exception, that the developer can check in the error console.

There is no standards-based way to do this. The closest thing is this.
The closest you could get to this would be:
function execute(obj, message, args) {
if (obj[message] && typeof(message) === function) {
obj[message].call(obj, args);
} else {
obj[message] = function() {
//missing method functionality a la Ruby here
};
}
}

Others have already mentioned __noSuchMethod__ and Proxy so I'll refrain from going into further detail on those.
Instead, I wanted to highlight another technique that may be able to do what you want. Please be aware that this is a ugly hack, I can't encourage it's usage and it may not even work in all of your targets. With those caveats in mind, I present you with window.onerror:
window.onerror = function(err) {
if (/has no method/.test(err)) {
console.log('oh my: ' + err) // This is where you'd call your callback
return true
}
return false
}
;(function() {
this.foo() // will be caught by window.onerror
})()
This – at least in my very limited testing – catches TypeErrors (in Chrome at least, mileage may vary) that signified that the method could not be found. Here are some of the reasons why you should not do this:
window.onerror can only have one handler; if your handler is overwritten this won't work
It catches TypeErrors globally, not just for a specific object; i.e. lot's of false positives
It'll make it fun to debug for anyone coming in not knowing where to find this handler
It tightly couples any bit of code you have that relies on this behavior (bad, bad, bad!)
I don't think I can stress enough how much you really shouldn't be thinking of hacking this in. Use Proxy if you can, admit defeat if you can't.

Related

Externalize a function in a Typescript method while maintaining closure

Reworded:
A common pattern is to pass callback functions, such as with Mongoose's save (just for example and simplified - no error handling):
someMethod(req:Request, res:Response){
document.save( function(err){ res.status(200).send({message: 'all good'})});
}
I'd like to externalize the callback. You can do this this way:
var respond = function(err:any, res:Response){
res.status(200).send({message: 'all good'});
}
someMethod(req:Request, res:Response){
document.save( function(err){ respond(err, res)});
}
...but ideally I'd like to do this by just passing a function like respond without having to create a call back function to enclose respond. I wanted to know if this is possible. Since the anonymous function has access to res, I thought there might be some way to gain access to res in a function defined externally. It appears there is not a way to do this so I'll live with wrapping it.
My original question was trying to isolate the specific issue I was interested in - which is to gain access to the caller's variables implicitly. Doesn't seem like that is possible. Fair enough.
Original Question:
I'd like to externalize a bit of code I use frequently and I'm having trouble understanding closure in the context of a Typescript method. Take a look:
var test = function(){
console.log("Testing external: "+JSON.stringify(this.req.body));
}
class Handler {
static post(req: Request, res: Response){
(function(){
console.log("TESTING anon: "+JSON.stringify(req.body));
}) ();
test();
}
}
Besides the fact that this does nothing useful, in this bit of code, the inline anonymous function has access to the req object, but the test() function does not. this in test is undefined. Removing this to match the inline function doesn't help.
I believe if I were to bind on this for the call I'd just end up with a reference to the Handler class when I really want to bind on the post method.
My motivation for doing this is that I want to make a function that can be passed as a callback to a bunch of different request handlers. When I write the functions inline it all works, but when I externalize it I can't get a closure over the variables in the enclosing method. I've read "You Don't Know JS: this & Object Prototypes", and in pure Javascript I can manage to make these sorts of things work but I'm obviously doing something wrong here (it may not be Typescript related, maybe I'm just messing it up).
So bottomline - is there a way I can externalize the handler and get access to the method variables as if I were writing it inline? I could just create an inline anonymous function as the callback that calls the external function with all the variables I need, but I want to really understand what is happening here.
This is not an answer, but will hopefully give me enough feedback to give you one because its not at all clear what you're actually trying to accomplish here and whether or not you actually understand what the terms mean is an open question since you use them correctly one minute and sketchily the next.
var test = function(){
console.log("Testing external: " + JSON.stringify(this.req.body));
}
In strict mode this will throw an error, in sloppy it will try to access the req property of the global object which is not likely what you want.
(function(){
console.log("TESTING anon: "+JSON.stringify(req.body));
}) ();
The IFFE wrapper is completely unnecessary, it literally adds nothing to the party. So why include it?
static post(req: Request, res: Response){
console.log("TESTING anon: "+JSON.stringify(req.body));
test(); // is this the spot where you are 'in-lining?'
}
What I think you want is this:
var test = function(reqBody) {
console.log("Testing external: " + JSON.stringify(reqBody));
};
class Handler {
static post(req: Request, res: Response) {
test(req.body);
}
}

expect() with no actual expectations

The Problem:
Recently, while reviewing our existing test codebase, I've noticed a dangerous kind of typo/mistake when expect() was used without the "matching" part:
expect(page.filters.fromDateLabel.getText(), "After");
I'm pretty sure toEqual() was meant to be used here:
expect(page.filters.fromDateLabel.getText()).toEqual("After");
The problem with this is that jasmine would not fail the expectation in this case (well, obviously because nothing was actually expected). And this gets us to a more serious problem - nothing was actually tested in a test case - it was passing with no expectations made. We were getting a false sense of what was tested.
The Question:
I want to catch these mistakes as fast as possible. How do you think I should handle the problem?
Thoughts:
somehow fail a test case if there was no expectations made in it (not sure if jasmine has anything like this built-in)
"patch" the expect() and issue a warning/raise an error if nothing was called on the "expect" part
use static code analysis - define a custom eslint rule
The custom ESLint rule provided in the answer is now a part of eslint-plugin-jasmine 1.6.0:
valid-expect
Old Answer:
Here is a custom ESLint rule I've ended up with:
module.exports = function (context) {
return {
// checking "expect()" arguments
CallExpression: function (node) {
if (node.callee.name === 'expect') {
if (node.arguments.length > 1) {
context.report(node, 'More than one argument passed to expect()')
} else if (node.arguments.length === 0) {
context.report(node, 'No arguments passed to expect()')
}
}
},
// nothing called on "expect()"
'CallExpression:exit': function (node) {
if (node.callee.name === 'expect' && node.parent.type === 'ExpressionStatement') {
context.report(node, 'Nothing called on expect()')
}
}
}
}
It checks for 3 things:
more than 1 argument passed to expect()
no arguments are passed to expect()
there was nothing called on expect()
Here are the sample invalid expect() usages it currently catches:
expect(page.filters.fromDateLabel.getText(), "After");
expect("After");
expect();
As for the option #1, there is actually a quite related and useful ESLint rule being already implemented and open-sourced by [eslint-plugin-jasmine]:
Enforce expectation (missing-expect)
I tend to think that the static analysis route is best, but if you’re looking for a quick and dirty way, here’s some code that grabs the expectations returned by all calls to expect and creates a proxy that tracks whether any of the expectation’s properties were ever used:
var unusedExpectations = new Set();
var originalExpect = window.expect; // Should be empty after every spec
var expect = function() {
var rawExpectation = originalExpect.apply(this, arguments);
unusedExpectations.add(rawExpectation); // Assume unused until used
// Traverse expectation and its prototypes, copying all properties to
// our proxy object. (Note that this becomes much simpler if you have
// ES6 Proxy in your environment.)
var proxy = {}
for(var proto = rawExpectation; proto; proto = proto.__proto__) {
Object.getOwnPropertyNames(proto).forEach(function(prop) {
if(Object.getOwnPropertyDescriptor(proxy, prop))
return;
Object.defineProperty(
proxy, prop, {
get: function() {
// Aha! Somebody used this expectation for _something_.
unusedExpectations.delete(rawExpectation);
return rawExpectation[prop];
}
}
);
});
}
return proxy;
}
Put that in a place where it hides Jasmine’s expect from your specs, and then:
beforeEach(function() {
unusedExpectations.clear();
});
afterEach(function() {
expect(unusedExpectations.size).toEqual(0);
});
Caveats:
Kind of evil.
Will not catch expect(foo).toBeFalsy; (missing parens).
Counts the use of any property, so won’t catch expect(foo).toString().
Still, it works!
One could add code to inspect the stack trace and extract the location of the offending expect(), but I imagine flagging which spec has an unused expect() is sufficient.

Javascript throw vs. return error object vs. callback

I'm writing an assembler and simulator for a toy assembly language that I have my CS students use in class. I'm writing it in javascript with the idea that I could then build a simple UI in the browser which would show students how each instruction changes the state of the machine and such.
One question that I'm grappling with is the best way to return error information from the assembler when invalid assembly code is passed. The assembler has an extremely simple API at the moment:
var assembler = ... // Get the assembler object
var valid_source = "0 mov r1 r2\n1 halt";
var valid_binary = assembler.assemble(valid_source); // String containing 0's and 1's
var invalid_source = "foo bar baz!";
var invalid_binary = assembler.assemble(invalid_source); // What should happen here?
I have a few thoughts about how this might work:
Construct and throw a new javascript Error object. This seems like overkill (and ultimately maybe not even helpful since the user wouldn't care about the javascript stacktrace, etc).
Return a string or object containing error information. Then the user of the assembler gets to make the choice about what to do with errors (if anything).
Change the assembler API to use a callback instead:
assembler.assemble(source, function(binary, error) {
if (error) {
// Handle the error
}
// Otherwise, do stuff with the binary
});
Something else entirely?
Any ideas, thoughts, or feedback would be much appreciated.
I think your three options would work fine. Now from my perspective:
I would keep away from the third option because it gives the feeling it is an async function when it is not.
I would go for option 1 or 2. The first one is a little overkill but I think it is the most realistic approach to what compilers do. Exit with no zero code. But then you would need to add a try/catch block to handle the error.
So the next option is to return an error object. Seems the best option for me.
I recommend you to return an Error object. It is as simple as:
return new Error('Parsing error');
// Or with an error name
var error = new Error('Parsing error');
error.name = 'PARSING_ERROR';
return error;
One advantage to use the error object is that it gives you the stack trace and other handy stuff. More info here.
Also, to check if there was any error just need to check the variable type:
if (typeof valid_binary === 'string') { /* no error */ }
// Or
if (typeof valid_binary === 'object') { /* error */ }
Good luck!

jquery vs google closure ajax

I've been looking into the google closure library for ajax calls, and I've gone through an example that looks like:
goog.events.listen(request, "complete", function(){
if (request.isSuccess()) {
// do something cool
} else {
// display an apologize message
}
});
As opposed to a jquery example that looks something like:
$.ajax({url: url, success: function () { }, error: function () { }});
I've been seeing google closure popup a lot more, but what would be the advantage or disadvantage in this case? The jquery library calls just seem a lot simpler for ajax related calls like this one.
Your Closure sample is incomplete. I assume just before your sample you created an XhrIo instance and called send() on it.
If you want a simpler Closure equivalent to the jQuery sample you posted you can use the static XhrIo.send(). It would look something like this:
goog.net.XhrIo.send(
url,
function(event) {
var xhr = event.target;
if (xhr.isSuccess()) {
// do something cool
} else {
// display an apologize message
}
});
That's admittedly clunkier than the jQuery version. In general, Closure is designed with object-oriented programming in mind (in stark contrast to jQuery which is mostly static functions). This may suit you or not, depending on whether you prefer to write your JS code in an object-oriented way.
In this particular case you might get a small advantage out of Closure if you create an XhrIo object that you reuse for multiple requests (e.g., you can setTimeoutInterval() on it to be used for all requests). If you care about memory, Closure may also give you more explicit control over garbage collection.

Can dynamically loaded JavaScript be unloaded?

I am writing a web application that has a static outer "shell" and a dynamic content section. The dynamic content section has many updates as users navigate the system. When a new content block is loaded, it may also optionally load another JavaScript file. In the name of good housekeeping, I remove script blocks from the DOM that apply to old content blocks, since that JavaScript is no longer needed.
The problem comes next, when I realized that although I have removed the <script> element from the DOM, the JavaScript that was previously evaluated is still available for execution. That makes sense of course, but I'm worried that it may cause a memory leak if the users navigate to a lot of different sections.
The question then, is should I be worried about this situation? If so, is there a way to force the browser to cleanup stale JavaScript?
<theory>You could go with a more object-oriented approach, and build the model in a way that each block of javascript blocks come in as their own objects, with their own methods. Upon unloading it, you simply set that object to null.</theory>
(This is fairly off-the-cuff.)
Memory use is indeed an issue you need to be concerned with in the current browser state of the art, although unless we're talking about quite a lot of code, I don't know that code size is the issue (it's usually DOM size, and leftover event handlers).
You could use a pattern for your loadable modules that would make it much easier to unload them en mass -- or at least, to let the browser know it can unload them.
Consider:
window.MyModule = (function() {
alert('This happens the moment the module is loaded.');
function MyModule() {
function foo() {
bar();
}
function bar() {
}
}
return MyModule;
})();
That defines a closure that contains the functions foo and bar, which can call each other in the normal way. Note that code outside functions runs immediately.
Provided you don't pass out any references to what's inside the closure to anything outside it, then window.MyModule will be the only reference to that closure and its execution context. To unload it:
try {
delete window.MyModule;
}
catch (e) {
// Work around IE bug that doesn't allow `delete` on `window` properties
window.MyModule = undefined;
}
That tells the JavaScript environment you're not using that property anymore, and makes anything it references available for garbage collection. When and whether that collection happens is obviously implementation-dependent.
Note that it will be important if you hook event handlers within the module to unhook them before unloading. You could do that by returning a reference to a destructor function instead of the main closure:
window.MyModule = (function() {
alert('This happens the moment the module is loaded.');
function foo() {
bar();
}
function bar() {
}
function destructor() {
// Unhook event handlers here
}
return destructor;
})();
Unhooking is then:
if (window.MyModule) {
try {
window.MyModule();
}
catch (e) {
}
try {
delete window.MyModule;
}
catch (e) {
// Work around IE bug that doesn't allow `delete` on `window` properties
window.MyModule = undefined;
}
}
If you save the evaluated code in namespaces, such as:
var MYAPP = {
myFunc: function(a) { ... }
}
"Freeing" the whole thing should be as simple as setting MYPP to some random value, ala
MYAPP = 1
This does depend on there being no other means of referencing the variable, which isn't trivial
How about loading the JS files into an iframe? Then (in theory, never tested it myself) you can remove the iframe from the DOM and remove the "memory" it's using.
I think... or I hope...
If you are worried about memory leaks then you will want to make certain that there is no event handlers in the code you want removed referring to the still existing dom tree.
It may be that you need to keep a list of all event handlers your code added, and before unloading, go through and remove the event handlers.
I have never done it that way, I always worry about when I remove nodes that there is still a reference.
Here is a good article on javascript memory leaks:
http://javascript.crockford.com/memory/leak.html
JavaScript interpreters have garbage collectors. In other words, if you don't reference anything, it won't be keeping them around.
One of the reasons why it is good to use JSON with a callback function (JSONP).
example, if you HTTP response for each JS is:
callback({status: '1', resp: [resp here..]});
And if callback() does not create a reference to the JSON object passed in as an argument, it will be garbage collected after the function completes.
If you really need to make a reference, then you probably need that data around for some reason - otherwise you would/should NOT have referenced it in the first place.
The methods mentioned to namespace objects just creates a reference that will be persisted until the reference count comes to 0. In other words, you have to track every reference and delete it later, which can be hard when you have closures and references from DOM lying around. Just one reference will keep the object in memory, and some simple operations may create references without you realizing it.
Nice discussion. Clears up a lot of things. I have another worry, though.
If I bind window.MyModule.bar() to an event, what happens if the event accidentally gets triggered after window.MyModule is deleted? For me, the whole point of namespacing and separating js into dynamically loaded modules is to avoid triggering event handlers cross-module by mistake.
For example, if I do (excuse my jQuery):
$('.some-class').click(window.MyModule.bar);
What happens if I delete window.MyModule, load another module, and click on an element which accidentally has a class called some-class?

Categories