Reading through this article about good interview questions for a JS coder linked off of HN today and got to the following part:
Next I'd ask a few simple questions designed to show me how well
candidates understood the arguments object. I'd start off by calling
the as-yet undefined log function.
log('hello world')
Then I'd ask the candidates to define log so that
it proxies its string argument to console.log(). The correct answer is
something along these lines, but better candidates will often skip
directly to using apply.
function log(msg){
console.log(msg);
}
Once that's defined I change the way I call log, passing in multiple
arguments. I make clear that I expect log to take an arbitrary number
of arguments, not just two. I also hint to the fact that console.log
also takes multiple arguments.
log('hello', 'world');
The way that the writer explains his solution is via apply:
Hopefully your candidate will jump straight to using apply. Sometimes
they'll get tripped up on the difference between apply and call, and
you can nudge them to the correct direction. Passing the console
context is also important.
function log(){
console.log.apply(console, arguments);
};
I get here that the log function is leveraging apply and implicitly passing arguments in, so that a call like
log('hello', 'world');
will pass along console.log.apply(console, ['hello', 'world']), though my question is: what is the console context in this example, i.e. the first argument in the apply call above, and where does it come from?
console is just the object that has the log function defined on, and is, essentially, this in the log function, which is why it is being passed as the context. console is not some special word in the browser, it's just an object that was saved under window.console.
Related
Is it possible to make an object callable by implementing either call or apply on it, or in some other way? E.g.:
var obj = {};
obj.call = function (context, arg1, arg2, ...) {
...
};
...
obj (a, b);
No, but you can add properties onto a function, e.g.
function foo(){}
foo.myProperty = "whatever";
EDIT: to "make" an object callable, you'll still have to do the above, but it might look something like:
// Augments func with object's properties
function makeCallable(object, func){
for(var prop in object){
if(object.hasOwnProperty(prop)){
func[prop] = object[prop];
}
}
}
And then you'd just use the "func" function instead of the object. Really all this method does is copy properties between two objects, but...it might help you.
ES6 has better solution for this now. If you create your objects in a different way (using class, extending 'Function' type), you can have a callable instance of it.
See also: How to extend Function with ES6 classes?
Following the same line of #Max, but using ES6 extensions to Object to pass all properties and prototype of an object obj to the callable func.
Object.assign(func, obj);
Object.setPrototypeOf(func, Object.getPrototypeOf(obj));
Others have provided the current answer ("no") and some workarounds. As far as first-class support in the future, I suggested this very thing to the es-discuss mailing list. The idea did not get very far that time around, but perhaps some additional interest would help get the idea moving again.
https://esdiscuss.org/topic/proposal-default-object-method
"CALLABLE OBJECTS"
I haven't seen mention of this type of answer yet.. but this is how I do "callable" objects:
<< PSEUDO CODE >>
{...objectWithFunctionsInside}[keyString](optionalParams)
short example defining first, simplest and preferred method if I just want a "callable object," in my definition:
let obj = {
o:()=>{return("oranges")},
b:()=>{return("bananas")},
s:"something random here, doesn't have to be functions"
}
obj["o"]()
short example of nameless object being run within a function's return, with parameters (note parameters works in the first example too):
function autoRunMyObject(choice,param){
return{
o:(p)=>{return(p+"oranges")},
b:(p)=>{return(p+"bananas")},
}[choice](param)
}
autoRunMyObject("b","orange you glad I didn't say ")
and that's pretty much it
You could even get weirder with it and do nameless functions that auto-run themselves and produce an output right away... for no reason, lol.
... hit F12 and copy this code into your browser console and press enter, you'll get an output right away with the full string:
((autoparam="o")=>{return{
o:(p)=>p+"oranges",
b:(p)=>p+"bananas",
}[autoparam]("I guess this time it's ")})()
You could even pass in the string of "b" in the final parenthesis for a different output from the default "o".
Also, each of my examples (minus the pseudo code first example) are easily copy/paste-able into the browser console for quick testing -- it's a nice place to experiment with JS.
In summary -- this is how I like to do "callable objects"
It's much better than
SWITCH(){CASE:BREAK;};
statements and
IF{}ELSE IF(){}ELSE IF(){};
chains.
I was looking through the React source and stumbled across a requirement with var emptyFunction = require('fbjs/lib/emptyFunction');.
I looked at this function and was confused by what it does.
Here is the function
function makeEmptyFunction<T>(arg: T): (...args: Array<any>) => T {
return function() {
return arg;
};
}
const emptyFunction: (...args: Array<any>) => void = function() {};
In the comments, they give the following explanation which I was confused by:
This function accepts and discards inputs; it has no side effects.
This is primarily useful idiomatically for overridable function
endpoints which always need to be callable, since JS lacks a null-call
idiom ala Cocoa
I have never come across null call idiom and was hoping someone could clarify what this means and explain the purpose of this function in less technical language.
Hopefully this question will not get looked down on because it isn't exactly code related. Maybe it belongs somewhere else, if so I'm sorry.
When programming in JavaScript, we can take a function as a parameter to a certain operation. As an example, a function may have a callback which is invoked after some kind of event.
function doIt(callback) {
// some work
callback();
// more work
}
Now if this callback is an optional parameter and it's not provided, we will get Uncaught TypeError: callback is not a function error because callback is undefined. There are two solutions to this issue. The obvious one is checking the callback with an if statement. Another option is set an empty function as the default value of callback if it's not assigned. This approach is very useful and shines if we have multiple places which invoke the callback function. So we don't need to check it for undefined every time before calling it.
function doIt(callback) {
callback = callback || function(){};
// some work
callback();
// more work
}
Likewise, there are lots of use cases where we can have overridable functions variables. It's a common pattern to set these type of variables to empty function as the default value so that we can call them without worrying about whether those are assigned/overridden or not.
Also, in some special cases, it's useful to have functions which do nothing but return a particular value. makeEmptyFunction is used for creating such functions. Basically, it returns a function which does nothing but returns what ever the parameter pass to it.
emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
As you can see in the file, above code generate an empty function which returns false value.
"null call idiom" is something we find in Objective-C/Cocoa programming. It basically allows you to call a method of an uninitialized object (null pointer) without giving any errors like in most of the other languages. I think that's what the author have tried to explain in the comment.
Since JavaScript doesn't have such language feature, we explicitly achieve it using empty functions. Some people call it no-op or noop and you can find similar helpers in other popular JavaScript libraries such as JQuery and AngularJS also.
why does this work ?
<html>
<body id = "body">
<div id="para">hello world, invalid js API signature doesn't throw error !!!</div>
<script>
var temp = document.getSelection("parameter");
</script>
</body>
</html>
getSelection() does not take any parameter as per standard signature.
I have tested this and it does not throw any error on JS console either.
JavaScript doesn't complain if you call a function with the wrong number of arguments. If there are fewer arguments passed than declared, the extra parameters have the value undefined. If there are more, they are simply ignored. This is a feature and not a bug!
Inside the JavaScript function you have access to the arguments value which is an array-like structure holding all the arguments passed to it. If you wanted you could define all your functions to take 0 parameters and use arguments[0], arguments[1], etc instead of the named parameters you previously had (though i don't see why one would do that) and the functions would still work exactly the same.
The benefits of having this arguments structure and no limits on how many arguments you call a function with allows you to do very powerfull things, like the bind polyfill found here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
If I have the following JavaScript function
function foo(first, last){
return "from Foo";
}
JavaScript will execute and will return for all of the following
foo();
foo(2);
foo("abc");
foo("abc", 3, 5);
If you want to deal with all the passed parameter. you can get those from "arguments".
MDN link
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.
JavaScript is a revelation to me. I thought it would be like another sort of classical languages like C#, Java, etc. But it didn't. "Dynamic world" is tough and unpredictable. I was astonished when I read that functions can receive as many parameters as you desire. Without any error! I don't like it at all. I want more "staticness", I want some sort of compile-time errors!
My question is: am I need to worry about that? Is it a good practice to throw an exception if a quantity of passed parameters are more than a particular function expects?
function foo(one, two, three)
{
// Is it good?
if(arguments.length > arguments.callee.length)
throw new Error("Wrong quantity of arguments in " + arguments.callee.name + "()");
/* Stuff */
}
foo(1, 2, 3, 4); // -> Error
foo(1, 2, 3); // -> OK
Should I be concerned about it at all?
Thanks in advance!
You probably should not be concerned. There is no blanket rule on how to handle errors like this. It depends entirely upon the type of error and the type of situation. In some cases, where it's a serious programming error and there is no way to proceed (like insufficient arguments to perform the desired function), it may make sense to throw an exception or return an error from the function. But, in other cases, an extra argument can just be safely ignored and you can continue on your merry way as if that argument was never passed.
As you get used to javascript, you will come to understand that many function arguments can be optional and a single function may be correctly called with zero, one, two or three or even N arguments and the code in the function can adapt appropriately. This actually allows you to do things that are not as easy to do in more "static" languages. It is even possible to adapt to the type of the arguments and do something appropriately based on the type of the argument. While this may sound like heresy to someone that only has experience in hard-typed languages, it can actually be extremely useful.
As you maintain a body of code over time, you will also come to find that it's nice to be able to add an argument to the definition of a function, add code to that function that defaults it to a reasonable value if it isn't passed and NOT have to change any of the prior code that was using that function, yet a few new places that need that new argument can start using it immediately. Rather then grepping through the entire codebase to fix up every caller of that function, you can just make one change in one file and immediately start using a new argument to the function without changing all the other callers. This is enormously useful.
So, in more direct answer to your question, an extra argument passed to a function is never a serious error in javascript. Your code could just ignore it and proceed. If you want to alert the developer who wrote that code that an unexpected argument was passed, you can notify them somehow (perhaps some warning text on the debug console) in the "debug" version of your function/library, but I see no reason why you should stop execution in the "production" version of your function/library when you can proceed without any harm.
You don't need to worry about this. If you pass too many arguments, the function will just ignore it. You should only throw an error if there are too few arguments. In that case, the function might not be able to run.
While I agree that the number of arguments aren't important (and won't cause a problem so long as you type-check the arguments you're getting before you use them), since an unused, uncalled, argument won't do anything, if you're particularly concerned you could just create a subset of the passed-arguments and access that object internally:
function test(arg1, arg2, arg3) {
var slice = Array.prototype.slice,
subset = slice.call(arguments, 0, 3); // depending on how many arguments you want
}
Of course this means that you've now got to recover the parameters from the args object, and since surplus arguments seem to be perfectly safe this seems pointless. But it is still an option.
Albeit unnecessary.