I'm currently reading up on "Content-based publish/subscribe" design patterns and in one of the implementations it suggests subscribing to an event using expressions in string form ie. eventMiddleware.on("foo===bar && bool",callback).
However I'm not quite sure how to handle the string expression middleware side.
I'm constantly reading about how eval is "evil" and that I shouldn't use it, but is it appropriate in this case? Is there a better method? or should I just simply stay away from registering events with expressions entirely?
If "foo===bar && bool" is produced server-side just replace it with function (x) { return x === bar && whatever-you-need; }. Code your way around so that you evaluate the function by just calling it. You won't need eval at all if you can get this far.
The predicate is a guard. Say you define it this way:
function on(guard, callback)
{
}
Then, in your pattern, the message dispatcher should just do this:
if (tyepof(guard) === "FUNCTION" && guard(arg))
{
callback(arg);
}
I hope this is comprehensible.
Related
I have read this In Javascript, how to conditionally add a member to an object? but in my case, it doesn't work.
I have the following situation:
angular.forEach(vm.someData.entities, entity => {
...(entity.type === "section" && { entity.styleFormats = entity[`${vm.activeTab}StyleFormats`]});
entity.content = entity[`${vm.activeTab}Content`];
entity.stateClasses = determinateStateClasses(false);
entity.isNew = false;
});
The spread operator gives me a parsing error.
Don't use the spread operator here. That operator is used when constructing an object literal, which isn't what you're doing here. You're simply writing a line of code in a function.
You may be able to use && short circuiting to perform the intended operation:
entity.type === "section" && entity.styleFormats = entity[`${vm.activeTab}StyleFormats`];
But this is a little unclear. Normally this kind of short-circuiting is used when resolving to a value, not when performing an operation. Think of this as structurally like the difference between using the conditional operator (?:) vs. using an if block. The former is not a drop-in substitute for the latter, they have their own uses.
In this case what you're looking to do is conditionally perform an operation within your function. That's exactly what an if block is for:
if (entity.type === "section") {
entity.styleFormats = entity[`${vm.activeTab}StyleFormats`];
}
Basically, don't try to write the cleverest code possible, write the clearest code possible. There's no reason to avoid using an if block.
I'd like to write a JavaScript class that works like C#'s IQueryable<T> interface to enable nicely-formatted queries against a remote data source. In other words, I'd like to be able to write the following (using ES6 arrow syntax):
datasource.query(Sandwich)
.where(s => s.bread.type == 'rye')
.orderBy(s => s.ketchup.amount)
.take(5)
.select(s => { 'name': s.name });
and turn that into something like
SELECT s.name AS name
FROM sandwich s
JOIN bread b ON b.sandwich_id = s.id
JOIN ketchup k on k.sandwich_id = s.id
WHERE b.type = 'rye'
ORDER BY k.amount
LIMIT 5;
with the SQL query (or whatever query language is used) being actually sent to the server. (Doing the filtering on the client side is not feasible because the server might return tons of data.)
In C#, this functionality is supported by the Expression class, which lets you construct an expression tree from a lambda function. But JavaScript has no equivalent, as far as I know. My original plan was to feed f.toString() to Esprima's parser for the function f passed as the argument to select(), where(), etc. and use that expression tree. This approach works great as long as the expressions refer only to literals, but when you try something like
var breadType = 'rye';
datasource.query(Sandwich)
.where(s => s.bread.type == breadType)
...
it fails, because you'll have a token breadType that you can't replace with a value. As far as I can tell, JavaScript has no way to introspect the function closure and get the value of breadType after the fact externally.
My next thought was that since Esprima will give me a list of tokens, I could modify the function body in-place to something like
return {
'breadType': breadType
};
and then call it, taking advantage of the fact that even if I can't access the closure, the function itself can. But modification of a function's code in-place also seems to be impossible.
Another approach that would not require Esprima would be to pass in a sentinel object as the argument to the inner function f and override its comparison operators, which is how SQLAlchemy's filter() works in Python. But Python provides operator overloading and JavaScript does not, so this also fails.
This leaves me with two inferior solutions. One is to do something like this:
var breadType = 'rye';
datasource.query(Sandwich)
.where(s => s.bread.type == breadType)
.forValues(() => {
'breadType': breadType
});
In other words, I could force the caller to provide the closure context manually. But this is pretty lame.
Another approach is to do the sentinel object thing but with functions instead of operators since operators can't be overloaded:
var breadType = 'rye';
datasource.query(Sandwich)
.where(s => s.bread.type.equals(breadType));
ES6's Proxy objects will make this simple to implement, but it's still not as good as the version with regular operators.
Sorry for the long post. My ultimate question is whether it's possible to achieve this with the ideal syntax shown in the first code block and, if so, how to do it. Thanks!
No, this is indeed impossible for the reasons you outlined. If you want to support passing arbitrary closures as arguments, then your only choice is to execute the functions. You cannot transform them to SQL statements, at some degree this will always fail regardless how many static code analysis you perform on the files.
I guess your best bet here are template literals, where you could have something like
var breadType = 'rye';
datasource.query(Sandwich, `
.where(s => s.bread.type == ${breadType})
.orderBy(s => s.ketchup.amount)
.take(5)
.select(s => { 'name': s.name })
`)
so that you can keep your syntax as you want, but will have to supply all external variables explicitly.
We have an object (referenced by data) and we want to retrieve the value of a nested property. Ideally, we would like to do it like so:
value = data.category3.section2.article4.title;
We cannot do this like so, because the above line throws a reference error if any of the mediate objects (category3, section2, or article4) are not defined (at the corresponding positions) inside the data object.
Now, to nullify any potential reference errors that might be thrown, we could just place the above line inside a try-catch statement:
try {
value = data.category3.section2.article4.title;
} catch (err ) {}
This works! However, I am not confident that relying on try-catch in such a way is a good practice. The alternative solution would be to manually traverse to the desired property value. I have written a compact utility function that accomplishes that:
function get( val, names ) {
names = names.split( '.' );
while ( val && names.length ) { val = val[ names.shift() ]; }
return val;
}
Now we can get the property value like so
value = get( data, 'category3.section2.article4.title' );
So, my question is:
Is the try-catch approach a valid solution? Or are there valid reasons why it should be avoided?
Btw, the try-catch approach is heavily biased in this thread: What's the simplest approach to check existence of deeply-nested object property in JavaScript?
Why not:
var value = data &&
data.category3 &&
data.category3.section2 &&
data.category3.section2.article4 &&
data.category3.section2.article4.title;
That is safe (if any of the objects in the traversal chain are not set, value will be null). That is a little neater than a bunch of if blocks, and avoids (?mis)using exceptions.
Another use of that method to provide a default value on failure:
var value = data &&
data.category3 &&
data.category3.section2 &&
data.category3.section2.article4 &&
data.category3.section2.article4.title || 'default value';
Both are fine. The only major differences between them I can think of are that
The try-catch may cause a debugger to unecessarily halt too often if you tell it to stop on all exceptions.
This is relevant you need to debug code that is swallowing exceptions. For example, some promise libraries wrap all callbacks in a try-catch block.
The string splitting version can't easily cope with properties that contain a dot in them
var x = {'.': {a: 17}};
try{ obj['.'].a }catch(e){}
get(/*???*/)
If you want something robust that avoids both pitfalls I would suggest a function that can (at least optionally) directly receive a list of properties.
get(val, ['prop1', 0, '.', 'category2']);
I think the differences here are going to be mostly contextual - it depends on the data you're trying to access and what you want to do with it.
For example, the second function will return equivalent undefined values for a variety of circumstances, including both data.category3 === undefined and data.category3.section2.article4.title === undefined. Using try/catch here tells you that you have an actual traversal error, rather than a property that hasn't been set, which you might want to handle differently.
Abusing try catch like this is a dirty hack.
Try catch is there to catch exceptions you throw. Exceptions are used for exceptional cases.
In this case both cases are wrong. You should never have to traverse data.category3.section2.article4.title; where every step can fail.
You should simply be able to assert that if data has a category then it should have a section, article and title.
I say refactor the code so you don't have multiple levels that can fail.
I have seen the answers here and I think that the traversing is your best move, but it looks quite bothersome. You can make a function that traverses it for you or you can use the almighty brototype library found at: https://github.com/letsgetrandy/brototype
This way you can do something like this:
if (Bro(data).doYouEven('category3.section2.article4.title')) {
value = data.category3.section2.article4.title;
}
or you can use a callback:
Bro(app).iDontAlways('category3.section2.article4.title')
.butWhenIdo(function(title){
value = title;
});
I think everyone should check this amazing library out, and code with great bro-ness.
If you dislike the brototype, you can indeed use your own get function.
I would like advice as to best practice in testing object existence for cross-browser compatibility.
There seem to be many ways of testing for object/function/attribute existence. I could use jquery or another library, but for now I want to stick as closely as possible to w3c rather than use what amounts to a whole new language.
What I'm trying to do
I'm trying to write a utility library that tries to stick to w3c methods so I can just call
xAddEventListener(elem, type, listener, useCapture)
for all browsers rather than
elem.AddEventListener(type, listener, useCapture)
just for w3c compliant browsers. If another library already does this, please let me know.
I saw this today:
if (typeof node.addEventListener == "function")
but will this ever yield a different result than plain
if (node.addEventListener)
Style documents?
A reference to a standards or styles document would also be useful. I've found https://developer.mozilla.org/en/Browser_Detection_and_Cross_Browser_Support
but that was last updated in 2003. It advocates simple
if (document.images)
tests for most existence tests and
if (typeof(window.innerHeight) == 'number')
only with numbers because if(0) would evaluate to false
Examples to inspire comment:
if (myObject)
Can an object or function ever fail this simple test?
if (myObject != undefined)
When is this better than the previous test?
if (typeof(myObject) == 'object')
This appears to be the original way of calling type of, but some people say that typeof is a keyword and not a function. Also, why not one of the simpler tests?
if ( typeof myObject.function !== undefined ) {
One post said to alway use === or !== as it differentiates between null and undefined. Is this ever important in practice?
Another possibility is:
try {
node.addEventListener(...)
}
catch(err) {
node.attachEvent(...)
}
Which in python appears to be becoming the favourite way of dealing with these type of things.
Using exceptions looks potentially much cleaner as you could write easy to understand w3c compliant code, and then deal with exceptions when they come.
Anyway, what do people think? Please can you list the pros and cons of methods you like/dislike, rather than simply advocating your favourite.
It all depends on how specific you want to be / how much you want to assert before calling a function.
if (myObject)
Can an object or function ever fail this simple test?
No, the only values that do not pass an if clause are false, 0, "", NaN, undefined and null. These are all primitives. Objects (including functions) will always pass an if clause.
if (myObject != undefined)
When is this better than the previous test?
If you want to check whether a value is "meaningful", i.e. not undefined or null. For example,
if(numberInputtedByUser) {
// do something with inputted number
}
will fail the if clause if the number is 0, while you probably want 0 to be allowed. In such case, != undefined is a slightly better check.
if (typeof(myObject) == 'object')
This appears to be the original way of calling type of, but some people say that typeof is a keyword and not a function. Also, why not one of the simpler tests?
It is a keyword. You can call it in a function-like fashion, though. In its most bare form you can use typeof like this:
typeof myObject
You can, however, add (extraneous) parens since they don't mean anything:
typeof (myObject)
Just like you can do:
(myObject).key
or even:
(((myObject))).key
And you can then remove the space after the typeof if you want, resulting in something that looks like a function call.
As to why to use typeof - you can be even more certain of the type of variable. With the if(...) test, the values that pass can be all kind of things - basically everything except the list I posted above. With if(... != undefined), you allow even more to be passed. With if(typeof ... == 'object'), you really only allow objects which might be necessary depending on what you're processing.
if ( typeof myObject.function !== undefined ) {
One post said to alway use === or !== as it differentiates between null and undefined. Is this ever important in practice?
=== is really preferred over ==. While differentiating between null and undefined is not always necessary, it is a very good practice to save yourself from the results of quirks like 0 == ''. If you want to check whether a number is 0, then === 0 is the way to go, since == 0 also allows for an empty string (which you might not expect and probably don't want). Even in cases == doesn't cause quirks, you'd be better off using === at all times for consistency and avoiding surprising bugs.
try {
node.addEventListener(...)
}
catch(err) {
node.attachEvent(...)
}
This is of course possible and very straight-forward. Note however that try catch is said to be slow. Moreover, you don't really account for why it fails. It's a bit simple-minded (but may work fine).
if (typeof node.addEventListener == "function")
but will this ever yield a different result than plain
if (node.addEventListener)
Yes, like I said above, the first only passes functions whilst the second allows anything except that list of "falsy" values. One could add Node.addEventListener = 123, and it will pass the if clause in the second case. But IE fails to give a correct typeof result:
typeof alert !== "function"
I bet the same goes for addEventListener so you'd still be avoiding that function even if it exists.
In the end, I would just use a simple if clause. Of course this will fail when you add weird things like Node.addEventListener = 123, but then again you're bound to expect weird things happen.
Let's have a function call
function doSomethingAndInvokeCallback(callback){
// do something
callback();
}
I can check if given argument is function if(typeof callback == 'function')
How can I discover, if given callback function is function and isn't empty?
like
doSomethingAndInvokeCallback(function(){
//nothing here
})
There is no totally reliable way to know if a function is empty because there are multiple kinds of functions in JS, some implemented with JS and some implemented with native code and you can't know for sure whether the function passed in does anything or not. If you want to limit the passed in function to only very simple JS functions, you could use the mechanisms outlined by other answers here (examining the source of the function). But, I would not recommend doing that in anything but a tightly controlled situation because there are lots of legal javascript ways to break that.
I would suggest that you should change the contract of your function arguments and have the caller pass null or not pass anything (which will make the argument undefined) rather than an empty function. Then, it will be very clear whether they intend to have a function called or not. If they then pass an empty function instead of null or undefined, they are getting the behavior that the interface of the function specifies. The caller can choose the desired behavior and you can implement your function in a more failsafe manner.
Also, one of your main suppositions in your question is not quite right. You cannot safely use typeof x == "function" to determine if something is a function as that will not work reliably in some older versions of IE for some types of functions. If you want to learn how to detect if something is a function at all, you can learn from jQuery here (even if you're not using it). jQuery has a function it uses internally all the time called jQuery.isFunction() that returns a bool. It uses that mostly for testing arguments to see if a function was passed.
Internally, it calls:
Object.prototype.toString.call(o)
and then examines the result. If the result has "Function" in it, then test test parameter is a function.
So, using the same technique used in jQuery, you could build your own simple little isFunction routine like this:
function isFunction(test) {
return(Object.prototype.toString.call(test).indexOf("Function") > -1);
}
Of course, if you have jQuery available, you could just use it's own version:
jQuery.isFunction(o)
When there are questions with potential cross browser compatibility issues, I find it instructional to look at how one of the big libraries solves the issue, even if you aren't going to be using that library. You can be sure that the libraries have been vetted against many browsers so a technique they are using is safe. You sometimes have to unwrap all their own internal routines they may use to figure out what they're really doing (which was the case for this function), but you can save yourself a lot of legwork.
You can see a working test bed for this here: http://jsfiddle.net/jfriend00/PKcsM/
In modern browsers typeof fn === "function", but in older versions of IE, some functions give a typeof === "object" which is probably why jQuery uses this other method which does work in those older versions of IE.
It seems that you can define a function to retrieve the body of a function(1). I wrote a small (non-definitive) test of this:
http://jsfiddle.net/6qn5P/
Function.prototype.getBody =
function() {
// Get content between first { and last }
var m = this.toString().match(/\{([\s\S]*)\}/m)[1];
// Strip comments
return m.replace(/^\s*\/\/.*$/mg,'');
};
function foo() {
var a = 1, b = "bar";
alert(b + a);
return null;
}
console.log(foo.getBody());
console.log(foo.getBody().length);
One possibility is matching the .toString result against a regexp to get the function body, and then trim to check whether it has become an empty string:
var f = function foo() {
};
/^function [^(]*\(\)[ ]*{(.*)}$/.exec(
f.toString().replace(/\n/g, "")
)[1].trim() === ""; // true
That ugly regexp does take care of spaces aroung named functions as well as extraneous spaces before the name and the opening brace. Spaces like in foo () do seem to be removed, so there is no reason to check for those.
You might be able to get this from .toString():
var blank = function(){};
var f = function(){};
var f2 = function() { return 1; };
f.toString() == blank.toString(); // true
f2.toString() == blank.toString(); // false
but this is really prone to error:
var blank = function(){};
var f = function(){ }; // extra space!
f.toString() == blank.toString(); // false
You could munge the strings a bit to try to overcome this, but I suspect this is very browser-dependent. I wouldn't actually try to do this in a production environment if I were you. Even if you normalize the whitespace, it still won't catch other no-op lines, including comments, useless var statements, etc. To actually address these issues, you'd probably need a whole tokenizer system (or a crazy regex).
You can't do it for a host function, but for others, you can fairly reliably do
function isEmpty(f) {
return typeof f === "function" &&
/^function[^{]*[{]\s*[}]\s*$/.test(
Function.prototype.toString.call(f));
}
This isn't efficient, but major interpreters implement toString for functions in such a way that it works, though it will not work on some interpreters for some empty-ish functions
function () { /* nothing here */ }
function () { ; }
function () { return; }
In some implementation you can just do a toString() on the function and get it's content. Though it contains comments etcetera.
var foo = function(){ /* Comment */ };
alert(foo.toString());