Tuesday, 18 August 2020

Javascript Functions

 A function is a block of organized, reusable code that is used to perform a single,related action.

Argument :

An argument is a value that we pass to the function when we invoke it.

Parameter :

A parameter is a variable that we list as part of a function definition.

The Arguments Object :

ex :

  function printAll{

     for(let i=0;i<arguments.length;i++){

  console.log(arguments[i]);

}

  }


 printAll(1,2,3,4,5); // 1 2 3 4 5

 printAll(10,20);     // 10 20


you can invoke a function with an indefinite number of arguments.

The arguments object allows us to represent them as an array-like object. 


Function scope :

A function scope is created for every function.

function iHaveScope(){

  // local function scope

  function iHaveNestedScope(){

    // nested local function scope

  }

}


Block Scope :

when we say block,we are referring to the code placed between curly braces.

The lifetime of variable within the curly brace {} of an if statement, a while, or a for loop,

or any set of curly braces other than a function.


ex : 

   let message='Hello';

   if(message ==='Hello'){

     let message = 'Inside if block';

console.log(message);   // Inside if block

   }

   

   console.log(message); // Hello

   



Note: variables declared with the var keyword or within function declaration

'DO NOT' have block scope.

There are three ways to declare variable in JS :

1. var width=100;

2. let height = 200;

3. const key = 'abc123';

Note : 'var' variable are 'function scope'.what does this mean?

It means they are only available inside the function they're created in,

or if not created inside a function, they are 'globally scoped'.

what is the block?

A block is a set of opening and closing curly brackets.

Note:

var is function scope.

let and const are block scope.

Function scope is within the function.

Block scope is within curly brackets.


Immediately Invoked Function Expression(IIFE):

The IIFE pattern let us group our code and have it work in isolation,

independent of any other code.


Function Expression :

Define a function and assign it to a variable.

Immediately Invoked 

Invoking the function right away where it's defined.


ex : (function () {

        console.log("Hello"); // Hello

     })();


Closures :

=========


let greeting = ( function () {

  let message='Hello';

  let getMessage= function(){

     return message;

  };

  

  return {

    getMessage : getMessage,

  };

})();  


console.log(greeting.getMessage()); // Hello


ex :

function setupCounter ( val ){

  return function counter(){

    return val++;

  }

}


let counter1 = setupCounter(0);

console.log(counter1());  // 0

console.log(counter1());  // 1

let counter2 = setupCounter(10);

console.log(counter2());  // 10

console.log(counter2());  // 11


Note : Each of them have their own environment and variables,

and anytime we call either counter1 or counter2, the variable that

was initially set up in the context is incremented.


Improving Readability with Arrow Functions :


Arrow Functions are introduced in ES6.

Simpler way to write a function expression.

--> shorter syntax

--> 'this' derives its value from enclosing lexical scope.

Arrow Functions are not really a substitute for regular functions.

Arrow functions have several side effects

1.Behavior of 'this' keyword.

2.No arguments object


Note : Arrow functions don't have their own implicit arguments object.

ex : 

   

   let greetings = () => {

       return 'Hello world!';

    };

   let message=greetings();

   console.log(message);   // Hello world!

   

ex :

    let greetings = () => 'Hello world!';

let message = greetings();

console.log(message);  // Hello world!


ex :

  let greetings = name => 'Hello '+name;

  let message = greetings('John');

  console.log(message);    // Hello John

  

Note : if you have only one input parameter ,

the parenthesis around it is optional.


ex :

  let sum =(num1,num2) => num1+num2;

  let output =sum(10,7);

  console.log(output);  // 17


Behavior of 'this' keyword :


In Javascript,'this' always refers to the owner of the function we are executing.


Note : In standard function, 'this' refers to the global window object

otherwise 'this' refer to the object that a function is a method of.


Note : Arrow functions do not have their own 'this' value.

The value of 'this' is always inherited from the enclosing scope.


ex :

  let message = {

    name:'john',

regularFunction : function(){

   console.log('Hello ' + this.name); 

},

arrowFunction : () => console.log('Hi '+ this.name)

  };

  

  message.regularFunction();   // Hello John

  message.arrowFunction();     //  Hi


 This is because when we log our message.regularFunction, our 'this' keyword refers to the message object that holds a function. 

 So when we access this.name, we get John. Let's print out the value of this inside the regularFunction. 

 As you can see, its value is the message object. Next, when we call message.arrowFunction, 

 it looks for the name variable in the global context,the Window object, and cannot find it. Therefore, only Hi gets printed to the console.  

Function Context and Built-in Functions :

Note : Anytime you invoke a function with a new keyword, javascript implicitly creates an empty object within the function before returning it.

ex : constructor Function


function SayHi(){

   console.log('Hi');

   console.log(this);

}

let greeting = new SayHi();

// Hi

// SayHi {} 


console.log(greeting) // SayHi {}


Note :

'this' in a normal function refers the 'global' object.

if it's in strict mode,'this' will be undefined.

And if the function is used with new operator, a new empty object will be assigned to 'this'.

Changing default context with call/apply/bind.

call Method :


ex : 

     let person1 = {name: 'John',age:22};

let person2= {name:'Mary',age:26};

let sayHi = function(){

    console.log('Hi, ' + this.name);

}

sayHi.call(person1) // Hi, John

sayHi.call(person2) // Hi, Mary

 

You can also pass additional arguments to the call method.


ex :

     let person1={name:'John',age:22};

     let sayHi = function(message){

    console.log(message+', '+ this.name);

}

     sayHi.call(person1,'Hi'); // Hi, John


apply Method :


ex : 


    function introduction(name,profession){

       console.log("My name is "+ name +" and I am a "+ profession+" .");

     }

introduction("John","student");                     // My name is John and I am a student .

introduction.apply(undefined,["Mary","lawyer"]);    // My name is Mary and I am a lawyer .

introduction.call(undefined,"James","artist");      // My name is James and I am a artist .


we are not really changing the function context of 'this' value here,

so we just pass 'undefined' as the first argument.  

 

Note :

call accepts an argument list,while apply accepts a single array of arguments.


apply vs call :


apply :

1.array input with similar elements.

call:

1.individual arguments of varying type.


with call and apply, we call an existing function and change the function context that is the value of the 'this' object.

 

Bind Method :

To make a copy of a function and then change the value of 'this'.

ex :

  let person1 = { name:'Mary',

                  getName : function(){

    return this.name;

  }

  };

  let person2 = {name: 'John'};

  let getNameCopy = person1.getName.bind(person2);

  console.log( getNameCopy());  // John


When we call bind on the person1.getName function and pass the person2 object 

as an argument, a new function is created and returned and assigned to the getNameCopy variable.

Additionally, the value of 'this' in the new function is set to the Person2 object.


Note : we are no longer changing the context of an existing function the way we 

did in call and apply,but instead create a new copy of function and then change its context to another object.


Built-in functions :

1. eval

Eval, as its name suggests, accepts a string as input, a valued set, and returns a value.


ex : 

 let x = 1;

 let y = 2;

 console.log(eval('x+y+1')); // 4

 

 ex :

  let x=1;

  let x=2;

  let s='abc';

  console.log(eval('x+y+s')); // 3abc

  

2.ParseInt

The function parseInt parses a string and returns an integer.

Optionally, you can also specify an additional base or radix argument to return an integer of that base.


The 'ParseInt' function converts its first argument to a string,parses that string,then returns an integer or NAN.


console.log(ParseInt('F',16));  // 15

console.log(ParseInt('15',10));  // 15

console.log(ParseInt('Hi',10));  // NaN


3.ParseFloat


ParseFloat works just like parseInt,but it returns a floating point number.


console.log(ParseFloat('3.99'))  // 3.99

console.log(ParseFloat('3.99e-1)) // 39.9

console.log(ParseFloat(''));      // NaN


4.Escape 

Escape returns the hexadecimal encoding of an argument in the isolated one character set.


console.log(escape('text')); // text

console.log(escape(' '));    // %20

console.log(escape('abc&%')); // abc%26%25


5.Unescape


Unescape does the opposite of escape, it returns the RC string for a given input value.



console.log(unescape('text')); // text

console.log(unescape('%20'));  //

console.log(unescape('abc%26%25)); // abc&%


Note :

call and apply methods change the context to another object.

bind method create a copy of a function and then change the function context.


Default and Rest Parameters and Spread Operator :


Default Parameters :


Default parameters allow you to give a default value to a parameter in a function.


ex : 

    function sayHi(name = 'World'){

  console.log('Hello ' + name);

}

 

sayHi();       // Hello world

sayHi('John'); // Hello John


ex : 

    function sayHi(message,name='World'){

console.log(message+name);

}

    

    sayHi('Hello');     // Hello World

    sayHi('Hi','John'); // Hi John


Note : The default parameter in function definition should always come after the regular parameters.

So in our sayHi function here, message cannot come after the name parameter.


Rest Parameters :


With rest parameters,you can define a function to store multiple arguments in a single array.

This is especially useful when you're invoking a function with multiple arguments.


ex : 

   let sayHi = function greet(...names){

     names.forEach(name => console.log('Hi ' + name));

 

   }

   

   sayHi('Mary','John','James');

   // Hi Mary

   // Hi John

   // Hi James

so the rest parameter really allows us to send any number of arguments to a function and then collect them in an array.


ex 2 :

        let sayHi = function greet(message,...names){

    console.log(message + 'everyone!');

names.forEach(name => console.log('Hi ' + name));

}

sayHi('Welcome','Mary','John','James');

// Welcome everyone!

// Hi Mary

// Hi John

// Hi James


Note : Just like the default parameters, rest parameters should appear after any regular parameters in your function definition.

rest parameter always stores the rest or remaining arguments as an array.


Spread Operator :


The spread operator is the opposite of how a rest parameter works.

it allows a function to take an array as an argument and then spread out 

its elements so that they can be assigned to individual parameters.


ex :

    function greet(name1,name2){

console.log('Hello '+name1+' and '+ name2);

}

    let names=['John','Mary'];

    greet(...names); // Hello John and Mary

ex : 

    function display(char1,char2,char3,char4){

  console.log(char1,char2,char3,char4);   


    let letters ='abcd';

    display(...letters); // abcd


so the spread operator can be used with any iterable like 

string,array or list.


ex :

    function display(char1,char2,char3,char4,...others){

  console.log(char1,char2,char3,char4);

      console.log(others);   


    let letters ='abcdefg';

    display(...letters); 

// abcd

//  ["e","f","g"]


Note : The rest parameter collects individual arguments and stores them in an array,

The spread operator takes an array as argument and spreads it into individual parameters.


No comments:

Post a Comment