I recently had an issue with some javascript that goes against every bone of my programming background. Javascript does this often to me, so I'm not that surprised.
I have a function as such...
function x(param1, booleanParam, arrayParam){
....
}
I was getting a runtime error saying that arrayParam.length was not defined. On debugging I saw this was true and went to find out why. Turns out I had forgotten a comma in my function call as such...
x(param1, true [arrayJunk]);
The problem I'm having is figuring out why this call was made at all? Why isn't this a compile error, how does Javascript see this and think, "Yeah, that seems like it might work!"
Thanks in advance for any enlightenment you can share!
That's an indexing expression.
It's the same syntax as someArray[someIndex].
It will end up passing undefined as the second parameter too, unless arrayJunk happens to be the name of a property of boolean primitives.
What happens is the following:
JavaScript engine converts true into a Boolean object (not the primitive)
It then tries to access the property name stored in arrayParam from that object
Property doesn't exist, so it returns undefined
If arrayParam was the string "toString", it would return a function object
In this case the expression was being interpreted as an index. Essentially the same as
someArray[42]
So it was being seen as a function call with 2 parameters instead of 3
Many dynamic languages don't check if you pass too many or too few arguments to a function.
While this can sometimes mask errors, it also allows you to roll your own defalut parameter scheme.
Related
Have a look at the last two answers.
How can we determine without looking into any documentation that sliderinput.value is the right answer, and not sliderinput.value()?
Im coming from Java. Im used to call accessor methods.
What is "value" as opposed to "value()"?
What is sliderinput if not an object?
You can determine this by checking if value is a function:
typeof sliderinput.value === "function"
Javascript usually doesn't use getter functions like value(). If you want to use getters you can use the get syntax to create a getter function that can be called using normal property syntax. See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
In the context of this quiz you've posted, I suppose they just want you to know from the top of your head that value is a property in this case.
How can we determine without looking into any documentation that sliderinput.value is the right answer, and not sliderinput.value()?
You can try it and see.
You can test its type (with the typeof operator) to see if it is a function or something else.
… but reading the documentation, despite you dismissing it, is the correct approach.
Note that the attribute value of sliderinput is a string, so the options with parenthesis () are not valid and will throw an error. You could do that only if value were a function type variable, which is not.
Edit: as other members pointed out, you can use typeof to check the variable type; in this case it will be "string"
This doesn't work:
var s = '^foo';
console.log(['boot', 'foot'].some(s.match));
Uncaught TypeError: String.prototype.match called on null or undefined
But this does:
var s = '^foo';
console.log(['boot', 'foot'].some(function(i) { return i.match(s) }));
Why is this? I imagine somehow the String.prototype.match function is too "primitive" or something, but why exactly? Since I'm not using ES2015, the second version seems quite verbose. Is there an alternative?
EDIT
When I wrote the above, I actually got it backwards compared to my actual need, which was matching one string against a number of regexes. But thanks to the great answers and comments below, I get it: [/^foo/, /^boo/].some(''.match, 'boot').
Note: The value of this is determined by how the function is called! (exception: bound and arrow functions)
If you pass s.match to .some, then the function will be called with this set to the global object (e.g. window) not the string it "belongs" to.
I.e. it would be equivalent to this:
String.prototype.match.call(window, 'foo')
This cannot work because this has to refer to a string object.
You could solve this by binding the function to a specific this value:
['boot', 'foot'].some(s.match.bind(s));
Learn more about this:
MDN - this
You Don't Know JS: this or That?
How to access the correct `this` context inside a callback?
A function value in Javascript does not bring its object along with it. The value of s.match is a plain function value, with no knowledge that you happened to find it attached to s. In fact, no matter what String you access it through, it's always the same function value:
"foo".match === "bar".match
//= true
When you call a function through an object, Javascript sets this to that object for the duration of the function call. But as soon as anything comes between retrieving the function value and calling it, any object association is lost.
You can create a function that does remember a specific this value using bind, as in #Felix King's answer. someFunction.bind(someObject) has approximately the same meaning as function(arg1, arg2,...) { return someObject.someFunction(arg1, arg2,...); }, but it automatically handles the number of parameters properly.
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.
Good day!
I stumbled upon something I've never seen in the realm of JavaScript, but I guess it's very easy to explain for someone who knows the language better. Below I have the following function: (Code taken from the Book: "Secrets of the JavaScript Ninja")
function log() {
try {
console.log.apply(console, arguments);
}
catch(e) {
try {
opera.postError.apply(opera, arguments);
}
catch(e) {
alert(Array.prototype.join.call(arguments, " "));
}
}
}
As you can see, the function is defined with an empty parameter list, but I was completely puzzled when I saw, later in the book, that they actually use said function like this...
var x = 213;
log(x); //Hmmm, I thought this function had an empty parameter list.
Could someone please explain to me, why is that function call allowed/possible? What are the concepts involved in JS that support this functionality? Thanks in advance, I'm very confused.
Best Regards,
You can call functions with the wrong number of parameters as much as you like. Excess parameters will be ignored; missing parameters will be given a default value.
As you can see from the code sample, you can access the arguments that were actually passed with the "arguments" object.
One of the design principles of JavaScript is to be forgiving rather than strict. If there's a way to keep going, JavaScript keeps going. Failing to pass a sufficient number of arguments is not considered fatal in JavaScript the way it would be in a language like C#, where one of the design principles is "bring possible errors to the developer's attention by failing at compile time".
Javascript functions have an implicit arguments parameter which is an array-like object with a length property.
for your log method you could do.
function log(){
alert(arguments[0]);
alert(arguments[1]);
}
And you can call log.
log("first","second");
JavaScript functions are variadic, i.e. they can take an arbitrary and infinite amount of arguments. You can access them via the arguments object, and pass in a variable number of values via apply. The formal parameter list just declares some variable names that are pointers to the arguments, and if there are less arguments given than parameter names defined they will default to undefined.
JavaScript allows you to call functions with any number of parameters, but if you'd like something more rigorous, there is TypeScript.
It prevents incorrect method calls and a lot of other JavaScript silliness.
I am trying to understand how to "chain" JavaScript events together like jQuery does. I found a question here on S.O. that was similar to my goal, but I do not understand the code in the answer.
Code Source
(function( window, undefined ) {
...etc...
}(window)
What does that mean? What is it doing? It reminds me of Jquery's $(document).ready(){} function, but I don't know why this person wrapped his code in this anonymous function that passes window and undefined.
My ultimate goal is to figure out how to execute methods on an object by chaining methods together like jQuery. I know that jQuery already does this but I am looking into this primarily for growth as a developer.
It defines a function (using a function operator as opposed to a function statement). The parenthesis around it ensure that it is treated as the operator rather than the statement.
It then executes it immediately, passing window as an argument.
Essentially, this is the same as:
var myFunction = function( window, undefined ) {
...etc...
};
myFunction(window);
… but without the interstitial variable.
This has nothing to do with jQuery style function chaining, where each method effectively ends with return this (so calling a method on the return value of another method is the same as calling it on the original object).
When a function is called with fewer arguments than its signature contains, the trailing arguments are assigned the value undefined.
So the above is a roundabout way of getting hold of the undefined value even if some lunatic has redefined it by saying var undefined= 'hello';. (This is illegal anyway in ECMAScript Fifth Edition's ‘strict mode’, but JavaScript coders do some weird things sometimes.)
There isn't really a good reason for passing in window like this though... the traditional way to get window if you can't rely on window is to call a function directly and use this.
Either way, this is simply defensive coding against pathological author JavaScript. It's not something you should worry about whilst writing your own code (in any case there's no way you can stop every way someone might mess up their JS environment), and it's nothing to do with chaining.