- Published on
Functions & Variables (Part III)
8 mins
- Authors
- Name
- Juleshwar Babu
 
 
Table Of Contents
- The "new Function" syntax
- Scheduling: setTimeout and setInterval
- Decorators and Forwarding, call/apply
- Function Binding
- Arrow functions revisited
- Content Updates
The "new Function" syntax
- Syntax: - let func = new Function ([arg1, arg2, ...argN], functionBody);- new Function('a', 'b', 'return a + b'); // basic syntax new Function('a,b', 'return a + b'); // comma-separated (present due to historical reasons) new Function('a , b', 'return a + b'); // comma-separated with spaces (present due to historical reasons)
- functionBodyis a string. These are useful when we need to create functions during runtime (getting function body from the server)
- Functions created with - new Function, have- [[Environment]]referencing the global Lexical Environment, not the outer one. Hence, they cannot use outer variables. But that’s actually good, because it insures us from errors. Passing parameters explicitly is a much better method architecturally and causes no problems with minifiers.
Scheduling: setTimeout and setInterval
- Syntax: - let setTimeoutId = setTimeout(func: Function |code: string, [delay]: number, ***[arg1]: any, [arg2]: any, ...***) let setIntervalId = setInterval(func: Function |code: string, [delay]: number, ***[arg1]: any, [arg2]: any, ...***)
- We can emulate the - setIntervalbehaviour using nested- setTimeouts. Frankly, that’s a more controllable way of running code regularly- let timerId = setTimeout(function tick() { alert('tick'); timerId = setTimeout(tick, 2000); // (*) }, 2000);- Also the behaviour aligns more with what we expect 👇🏼 - setInterval timeline - let i = 1; setInterval(function() { func(i++); }, 100); - setTimeout timeline - let i = 1; setTimeout(function run() { func(i++); setTimeout(run, 100); }, 100); - The nested - setTimeoutguarantees the fixed delay (here 100ms) in between running the business logic
Decorators and Forwarding, call/apply
- Decorators are functions which take a function and add additional functionality to it/alter its behaviour - function slow(x) { // there can be a heavy CPU-intensive job here alert(`Called with ${x}`); return x; } function cachingDecorator(func) { let cache = new Map(); return function(x) { if (cache.has(x)) { // if there's such key in cache return cache.get(x); // read the result from it } let result = func(x); // otherwise call func cache.set(x, result); // and cache (remember) the result return result; }; } slow = cachingDecorator(slow); alert( slow(1) ); // slow(1) is cached and the result returned alert( "Again: " + slow(1) ); // slow(1) result returned from cache alert( slow(2) ); // slow(2) is cached and the result returned alert( "Again: " + slow(2) ); // slow(2) result returned from cache
- calland- applyallow us to set the context when a function is run- func.call(context, ...args); func.apply(context, args);- There’s only a subtle difference regarding - args:- The spread syntax ...allows to pass iterableargsas the list tocall.
- The applyaccepts only array-likeargs.
 
- The spread syntax 
- Passing all arguments along with the context to another function is called call forwarding - let wrapper = function() { return func.apply(this, arguments); };
- Method Borrowing is a way of borrowing a method from one object to use it on another object - let arrayLikeObject = { 0: "a", 1: "b", 2: "c", length: 3 } // Result required: a,b,c using Array.join method [].join.call(arrayLikeObject)
Function Binding
let boundFunc = func.bind(context, ...args) // Any args provided during binding set fixed arguments for the function func
- An use-case - No context bound - let user = { firstName: "John", sayHi() { alert(`Hello, ${this.firstName}!`); } }; setTimeout(user.sayHi, 1000); // Hello, undefined **/** which essentially means let sayHi = user.sayHi setTimeout(sayHi, 1000) */**- this is lost - Context is present - This is one solution as the - useris just accessed from the outer Lexical Environment. But this solution has a problem. If the- userobject changes before the- setTimeoutruns, the code can break- let user = { firstName: "John", sayHi() { alert(`Hello, ${this.firstName}!`); } }; setTimeout(function() { user.sayHi(); // Hello, John! }, 1000);- To prevent issues as mentioned above, we can use bind which fixes the context in time to the function. So even if the - userobject is altered before the bound function runs, the bound function runs- let user = { firstName: "John", sayHi() { alert(`Hello, ${this.firstName}!`); } }; setTimeout(user.sayHi.bind(user), 1000); // Hello, John
 
Arrow functions revisited
- Link: https://javascript.info/arrow-functions
- Arrow functions:- Do not have this
- Do not have arguments
- Can’t be called with new
- They also don’t have super, but we didn’t study it yet. We will on the chapter Class inheritance
 
- Do not have 
Content Updates
- 2023-09-07 - init