Does a truthy value in JavaScript always have a hasOwnProperty method? - javascript

Here we can see which types of objects in JavaScript/ECMAScript evaluate to false.
My question is: if a variable evaluates to true, is it guaranteed to have a hasOwnProperty method?
In other words, is the following test safe?
if (bar && bar.hasOwnProperty("foo")) { ... }
My goal is to prevent exceptions like Cannot read property 'hasOwnProperty' of null.
My application scenario: in an AngularJS $http service error handler I want to be prepared for all situations. This is a little difficult for me, because I am not tremendously experienced with JavaScript and the different situations in which this error handler might be called can not easily be tested for. The error handler function has the following signature:
function(data, status, headers, config) {}
In the function body I evaluate data like so:
if (data && data.hasOwnProperty("error")) {
alert(data.error);
}
Does this look safe to you under all circumstances? Safe in the sense that this test does not throw an exception, no matter how AngularJS actually calls the error handler.

No.
Here's one:
var bar = Object.create(null);
Here's another one with hasOwnProperty, but not much better:
var bar = {hasOwnProperty:function(){ throw "bouh" }};
But you can call
Object.prototype.hasOwnProperty.call(bar, "foo")
Note that you may avoid the evaluation to truthy by doing
if (Object.prototype.hasOwnProperty.call(Object(bar), "foo")) {

Related

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.

Expose javascript errors in angular.js

in some cases, the angular engine doesn't output the raw javascript error. For example
myapp.directive('helloWorld', function() {
return {
scope: '#',
restrict: 'AE',
template: '<p ng-click="clearMessage2()">Hello, World! {{message}}</p>',
link: function(scope, elem, attrs) {
scope.clearMessage = function() {
scope.message = '';
}
}
}});
When I click on p element produced with directive I'm expecting the error in console to say clearMessage2() is not defined, but this doesn't happen and the only way to check things is to use console.log inside clearMessage definition.
Is it possible to change that behavior of angular.js and do not hide errors happening inside JS code?
It is possible, but not recommended. The problem is that angular does not execute the method in the ng-click directive as is (like in regular onclick), but instead evaluates expressions using the $parse service. From the angular doc:
Angular does not use JavaScript's eval() to evaluate expressions.
Instead Angular's $parse service processes these expressions.
The implementation of expression evaluation in Angular is deliberately forgiving.
In JavaScript, trying to evaluate undefined properties generates ReferenceError or TypeError. In Angular, expression evaluation is forgiving to undefined and null. It makes more sense to show nothing than to throw an exception if a is undefined (perhaps we are waiting for the server response, and it will become defined soon). If expression evaluation wasn't forgiving we'd have to write bindings that clutter the code
So the $parseProvider will not execute an undefined function at all, instead it will execute a noop function (which is an implementation of a null object pattern). Here is an excerpt from the $parseFunctionCall method:
var fn = fnGetter(scope, locals, context) || noop;
The execution of a null object will do nothing, and that is what's happening. You could probably achieve what you want by modifying the $parseFunctionCall to execute any function, instead of executing a noop function.
Changing code looks like the only option since configuration of these services is not sufficient for your use-case. However, i don't think it's a recommended approach unless you know the Angular API very well.
For additional reading:
Angular expressions
$parse service

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!

Calling a default method in Js Object

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.

null for elements in phantomjs

I have this code running in the phantomjs. I don't know why form.elements keeps returning null to me. I ran the same code on chrome developer console and got the right result i want.
I'm pretty new to javascript and everything related. Please shed some light.
var page = require('webpage').create();
page.open('http://www.kayak.com', function (status) {
if (status !== 'success') {
console.log('Unable to access network');
} else {
var form = page.evaluate(function(){
return document.getElementById('searchform');
});
console.log(form.elements[2].value);
}
phantom.exit();
});
You can't pass a non-primitive object through evaluate. This is mentioned in the documentation:
Note: The arguments and the return value to the evaluate function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine. Closures, functions, DOM nodes, etc. will not work!
Although it is the most common mistake when using PhantomJS, this is rather easy to solve. Just make sure you do all the processing as much as you can within evaluate and then return back a simple object. For details, please study the documentation carefully and learn from all the included examples.

Categories