JavaScript Jems - Lambda Expressions |
Written by Mike James | ||||
Thursday, 13 July 2023 | ||||
Page 2 of 3
Anonymous FunctionsThings are even simpler because you don't have to store a reference to a function to pass it to another function or to make use of it. As already described, other languages have to introduce something special to allow this to happen. In JavaScript it is just a consequence of the fact that all objects are anonymous and functions are objects. There is also the principle that anywhere you can use an object reference you can use an object literal. You could say that this is a mini-jem and while it isn’t generally useful it is worth knowing about. For example, instead of writing: var list=new Array("A","AB","ABC","ABCD"); list.sort(); you can use: var result=["A","AB","ABC","ABCD"].sort(); Anywhere you can use a variable that is a reference to an object you can use an object literal. JavaScript supports anonymous functions as object literals and you can write this example as: list.sort(function(a,b){ return a.length-b.length; }); The only real problem with this is how to format the line using indents that show where the function literal starts and ends. The indent shown above is one used by some automatic JavaScript formatters. An alternative solution is: list.sort( function(a,b){ return a.length-b.length; } ); which makes matching brackets slightly easier. For short functions a single line also works: list.sort(function(a,b){return a.length-b.length;}); This last example looks a lot like the typical way that lambda expressions are used in other languages. In C# you could write the same thing using: list.sort((a,b) => a.length-b.length) and the expression: (a,b) => a.length-b.length is a lambda expression. Notice that apart from being a little more compact - no need for the keywords function and return - it is more or less the same as a JavaScript anonymous function. Thus JavaScript, with its first class functions or functions as objects, doesn't really need lambda expressions or it already has them depending on your point of view. The Arrow FunctionJavaScript doesn’t really need anything like a lambda expression, but that didn’t stop one being added in ES2015 – the arrow function. While the arrow function isn’t strictly necessary, it does make JavaScript look more like languages which do have lambda expressions. The arrow function is mostly a condensed syntax for the function expression. You can use it to define a function as simply as: (param1,param2,…,paramn)=> {statements}; For example: (a,b)=>{ var ans=a+b; return ans; }; returns a Function object which can be used in the normal way. You can store a reference to the arrow function in a variable: var myFunction=(a,b)=>{ var ans=a+b; return ans; }; and you can call the function in the usual way: myFunction(1,2); You can use arrow functions as literals. So the previous example involving sort can be written: list.sort((a,b)=>{return a.length-b.length;}); You can see that this really does look like what other languages call a lambda expression. There are some syntactic shortcuts you can use that make arrow functions look even more like lambdas and make them even harder to read. For example, you don’t have to use a return. If you write a single expression then its value is automatically returned: list.sort((a,b)=> a.length-b.length); Notice that the expression isn’t within {} and you can only have a single expression. You can also omit the parentheses if the arrow function has only a single parameter. For example: a => a.length; is a function that returns the length of a. Finally an arrow function with no parameters has to use a pair of empty parentheses: ()=>{alert(“Hello World”)}; This is more or less all there is to an arrow function – with one exception. Arrow functions do not have a this of their own, they inherit whatever value for this is in use at the time of their declaration. This makes them less suitable for use as method definitions, but much better for passing to other functions as parameters. Otherwise everything that is true of a function expression is also true of an arrow function.In particular you can use rest parameters, default parameters and destructuring just as you can in a standard function. The only substantial difference, apart from the syntax, is the aforementioned way this is treated Accidental InvocationIs there a downside to having functions as objects? Perhaps the only real problem is the potential confusion between the object and the function or, more exactly, between the function and its invocation. You can create your own functions that accept other functions, but you have to be careful exactly how you do it and how you make use of them. For example: Say=function(t){ t(); } will simply call any function that you pass to it. If you define: Hello=function(){ alert("Hello"); } then: Say(Hello); will call the Hello function and display an alert. Notice that you have to pass the variable that references the function without accidentally invoking the function. That is, don’t write: Say(Hello()); by mistake as this would call the Hello function and then pass its result to the Say function which, as it is a string, couldn't be called as a function. Similarly, including parentheses in the parameter list in the definition of the function would be a syntax error. You need to distinguish very clearly between passing a function object and passing the result of a function to another function. This problem doesn’t occur in languages that restrict functions to being methods of objects. You then pass an object and you don’t think of trying to invoke it because it is an object not a function. |
||||
Last Updated ( Monday, 17 July 2023 ) |