I am curious how the typescript compiler is interpreting the colon in the incorrect call to the function foo.
const foo = (bar: boolean) => {
return bar;
}
foo(bar: true) // ERROR "Expected 1 arguments, but go 2."
This implies that it is interpreting both "bar" and "true" as arguments. To be clear, I am just curious how the compiler is parsing this.
As a follow-up, are there any legitimate uses of a colon in a function call except for in an expression that would result in an argument as in:
const baz = (bin: {bar: boolean})=>{
return bin.bar
}
baz({bar: true})
There are two errors generated for that line. One is indeed that the function expects two arguments, but the other one is that , was expected (this is the error you will see if you run the compiler).
The language service tries to offer as much diagnostics as possible even on invalid code.
The parser will try to parse bar as an argument (ie an expression) when it reaches the : it will stop parsing the argument expression as : can't be part of such an expression (at this time anyway). Then the compiler will continue to parse what it expects will be an argument list, and expect the ,, but finding the : instead. Now this is not a tragedy, the compiler will continue to parse the argument list, and interpret true as the next argument expression.
The semantic checks, will then see this call (with two arguments) as an attempt to call a function with one parameter with two arguments and give an error on that.
The reason you are probably seeing in your IDE the semantic error over the syntactic one is because the semantic error is associated with the whole call(foo(bar: true)) while the syntactic error is associated with just : (and if you hover over : you will see the ',' expected error)
As to your follow-up : can't be used directly in the argument list (like it can for example in C# for named arguments). The only valid use is if you use an object literal.
Related
It works fine:
const foo = 1; // any number, string, bolean or object
(() => console.log('stuff'))()
But it doesn't work without semicolon:
const foo = 1 // TypeError: 1 is not a function
(() => console.log('stuff'))()
Hm...
Should not the call of an anonymous function be treated as a separate instruction in the case when the first bracket can not be interpreted as a correct continuation of the previous instruction?
Yes, but it's only about syntactically correct continuations.
1(() => console.log('stuff'))()
is a syntactically correct expression and parses as "call 1 with an argument of () => console.log('stuff'), then call the result of that without arguments". This throws an exception at runtime (1 is not function, so it can't be called), but it's still a valid expression.
You should alway use semicolons. If you do not add them, Javascript will guess where to insert them and will lead to errors.
In your case, it is interpreting that you are calling a function.
A good article on the topic on how semicolons are automatically inserted:
The norm: The parser treats every new token as part of the current
statement, unless there is a semicolon that terminates it. The
following examples show code where you might think a semicolon should
be inserted, but isn’t. This illustrates the risks of omitting
semicolons.
No ASI:
a = b + c
(d + e).print()
This does not trigger ASI, because the opening parenthesis could follow c in a function call. The above is thus
interpreted as:
a = b + c(d + e).print();
…when the first bracket can not be interpreted as a correct continuation of the previous instruction?
But it can - as you can see, the code parses just fine, and executes. That it will throw a runtime exception when no semicolon isn't inserted doesn't matter to the ASI, it cannot know while parsing.
in javascript, it doesn't matter how many spaces you have, it will just be treated as one space only.
in your second code snippet, it just actually equals:
const foo = 1 (() => console.log('stuff'))()
which means you invoke a function called '1' and pass '()=>console.log('stuff')' as an argument. but apparently 1 is not a function, so it throw an error, hope make sense to you
How can I force Javascript (on Google Chrome) to be "less permissive" about a bad code?
I'd like to see an error in the Chrome console:
if a not-existing object key is accessed (instead of returning undefined)
if a function requiring N input arguments is called with only N-1 arguments (instead of setting the missing argument to undefined)
And, if possible, I'd like also to see "easier" errors like missing semicolon etc.
You could check the arguments.length to throw an error on missing arguments.
function foo (arg1, arg2) {
if(arguments.length !== 2) {
throw new Error("missing one argument")
}
}
foo("one");
Using semicolons to terminate a statement are optional in JavaScript, but you could use a linting tool to take care of that.
Check jslint for example.
While Chrome is excellent for debugging, it is not a replacement for a coding environment. There are many tools designed specifically to "lint check javascript" (JSLint for example).
Semicolons (terminating a line) are optional in Javascript, so no error should ever be thrown for missing semicolons in a runtime like Chrome.
I've declared two methods.
String.prototype.hazaa = function (shazoo) {
return this + shazoo;
}
Number.prototype.hazaa = function (shazoo) {
return this + shazoo;
}
When I call the former, I get the expected behavior. However, invoking the second one, produces the error below.
Syntax error: Unexpected token ILLEGAL(...)
I have the feeling that it's my C#-ishness that is spooking (I'm thinking extension methods and object oriented calls). The invocation's performed as follows.
"abc".hazaa("shazoo");
12345.hazaa(00000000);
Is there another syntax to invoke the function I've added? Have I not declared the prototype addition the right way?
Yes, I have made the research but I might be missing a relevant point.
The issue is while it is parsing 12345.hazaa(00000000);, it sees hazaa as coming after the decimal point in the number, hence the unexpected token. If you wrap the number in parentheses it is parsed and executed correctly:
(12345).hazaa(00000000);
It will continue to work normally on variables, as the parsing has already happened:
var a = 123;
a.hazaa(0000);
As mentioned by Jaromanda X in the comments, another alternative to allow correct parsing is to use a double-dot syntax:
12345..hazaa(00000000);
I just played with Twitter API and found very weird construction. It's division operator between function name and arguments passing.
c/({"count":8098,"url":"http:\/\/example.com\/"});
I supposed that this should throw parser exception, but it works − just returning NaN instead of undefined. Also it works similar with * and - operators, while + returns c.toString() (or .valueOf, I dunno).
Even more, it's really syntax error thrown if i don't pass object to function. Here's examples:
function c() {}
>> undefined
c
>> function c() {}
c/()
>> SyntaxError: Unexpected token )
c/({});
>> NaN
c+({})
>> "function c() {}[object Object]"
c({})
>> undefined
I ran this in Chrome, but I belive it works everywhere if Twitter put it in response.
So. Why this even work, and how it works exactly? I believe this somehow releated to function returning value and its implicit type coercion, but I still don't get it.
Your URL is not escaped in that API call so twitter reads it incorrectly and creates meaningless syntax.
If you set the URL parameter to an escaped value (via encodeURIComponent) it will produce c({some:"Object"}) which is a JSONP response - JSONP is inherently a function call and works by injecting a script tag.
So, twitter does not produce this response deliberately, you're passing it problematic parameters and it's not failing gracefully.
As for why dividing a function in an object is NaN - in JS generally math operators don't throw very often. JavaScript is telling you - you tried to perform a math operation that doesn't make sense and the result is not a number - NaN.
For the funky results:
c/()
Is just invalid syntax, simply put you're diving something by nothing, 5/() would fail equally well.
c/({})
Diving a function by an object makes no sense, so it is giving you "Not a Number". I can add a spec quote but I don't think there is much more to add beyond "There is no way to interperet this differently".
c+({})
The + operator performs string concatenation in addition to numeric addition - so what's happening here is that toString is called for both the function and the object and you see the concatenated result.
c({})
This is just the return value of the function call
I am investigating a bug in some software that has uses an in-house developed Javascript library. The error that I am dealing with appears on the line below:
GetVal1("dispLetter")(GetVal1("dispLetter").selectedIndex).value + '~' + (bFinal == true ? '1' : '0');
I initially wasn't sure if this line was even valid, however, according to source control this line was around since this file was created while the error is relatively recent. When I debugged I discovered that this line throws an error that says GetVal1(...) is not a function. I double checked to confirm that the Javascript file with the function definition is included, the header looks like this:
function GetVal1(strHTMLId)
So, I guess my question is, is this line valid Javascript code? Is there anything you can tell that could be throwing the error? Thank you.
GetVal1("dispLetter")(GetVal1("dispLetter").selectedIndex).value + ...
does the following:
calls GetVal1 with the argument "dispLetter".
calls GetVal1 with the argument "dispLetter", again.
retrieves the property selectedIndex of the return value of the second invocation of GetVal1
Calls the return value of the first invocation of GetVal1, with one argument, the value of selectedIndex. This fails your case, and complains the value is not callable.
The return value's value property is dereferenced. String concatenation follows.
In other words, this code seems to assume that the first invocation of GetVal1("dispLetter") returns a function (which is unusual), and the second invocation returns an object with the property selectedIndex (which is unusual, given the first invocation returns a function).
Some ideas:
If there used to be a new keyword before the line. Then the first invocation would be a constructor call. It is unexpected that a constructor call would return a function while a non-constructor call would not, though.
If there used to be a trailing period on the previous line (or is now), GetVal1 would refer (or refers now) to a property of some object. I smell a violation of naming conventions, though, if GetVal1 is meant to be an object property.
The global GetVal1 is (or recently ceased to be) shadowed by a function of the same name. Once again, I smell a violation of naming conventions.
Most likely, GetVal1 itself has changed. Verify GetVal1 can return a function when given this string as the first argument.
Perhaps the state bound to the GetVal1 function has changed (say, one more extra call somewhere before the code. This most likely a design error, though, if this function returns a different type of object on each invocation with the same arguments. But then again, there likely is a design error or naming violation somewhere in the code.
Another plausible explanation is that this line was there from the beginning, but it was never reached before. In this case, it could have been wrong the whole time.