Function
Define a Function
<button type = "button" onclick="f()">Click</button>
<script type="text/javascript">
	function f()
	{
		document.write("Hello World!");
	}
</script>
		
Return
function f()
{
	return Math.PI;
}

document.write(f());
		
Print the Function Definition
function f()
{
	return Math.PI;
}

document.write(f); // Call without ()
		
Mutable & Immutable
  • Immutable for primitive types, boolean/Boolean, null, undefined, string/String, and number/Number
  • Mutable for Array, Function, and Object
  • // immutable
    var a = 10;
    
    console.log('Before Calling the Function: '+a); // 10
    
    changeValue(a); // 100
    
    console.log('After Calling the Function: '+a); // 10
    
    function changeValue(v)
    {
    	v *= 10;
    	console.log('Inside Function: '+v);
    }
    		
  • both string and String are immutable, even the type of String is object
  • var s_1 = "Hello World!"; // immutalbe
    var s_2 = new String("Hello World!"); // immutable
    
    console.log(s_1 == s_2); //true
    console.log(s_1 === s_2); //false
    
    function change(s)
    {
    	s = s+"Changed";
    }
    
    change(s_1);
    change(s_2);
    
    console.log(s_1); // Hello World!
    console.log(typeof(s_1)); //string
    console.log(s_2); //String("Hello World!")
    console.log(typeof(s_2)); //object
    		
    // mutable
    function change(ob)
    {
    	ob.name = 'Yanhua';
    	console.log(ob);
    }
    
    var a = {name: 'Lin', age: 39}
    console.log(a); // {name: 'Lin', age: 39}
    
    change(a); // {name: 'Yanhua', age: 39}
    
    console.log(a); // {name: 'Yanhua', age: 39}
    		
    Anonymous Function
    var f = function (a, b) {return a+b;}
    
    console.log(f(10, 100));
    		
    Arrow Function
  • Immutable for primitive types, boolean/Boolean, null, undefined, string/String, and number/Number
  • Mutable for Array, Function, and Object
  • // regular function
    function add_1(a, b)
    {
    	return a+b;
    }
    
    console.log(add_1(1, 2));
    
    // arrow function
    add_2 = (a, b) => 
    {
    	return a+b;
    }
    
    console.log(add_2(1, 2));
    
    // single instruction in arrow function
    add_3 = (a, b) => a+b;
    
    console.log(add_3(1, 2));
    		
  • With a regular function this represents the object that calls the function
  • this keyword always represents the owner that of the arrow function
  • <button id="btn_1">Button 1</button>
    <button id="btn_2">Button 2</button>
    <script type="text/javascript">
    //The window own the function:
    window.addEventListener("load", () => {console.log(this)}); // window
    
    document.getElementById("btn_1").addEventListener("click", () => {console.log(this)}); // window
    
    //The window object calls the function:
    function info()
    {
    	console.log(this);
    }
    
    window.addEventListener("load", info); // window
    
    document.getElementById("btn_2").addEventListener("click", info); // button
    </script>
    		
    Default Arguments
    function f(a = 1, b = 2)
    {
    	console.log(a+b);
    }
    
    f(10, 100); // 110
    
    f(10); // 12
    
    f(b = 10); // 12, 10 is assigned to a
    		
    Keyword Arguments
    function f({a = 1, b = 2})
    {
    	console.log(a+b);
    }
    
    f({a:10, b:100}); // 110
    
    f({a:10}); // 12
    
    f({b :10}); // 11
    		
    const add = ({a = 1, b = 2}) =>
    {
    	console.log(a+b);
    }
    
    add({a:10, b:100}); // 110
    
    add({a:10}); // 12
    
    add({b:10}); // 12, 10 is assigned to a
    		
    Self-Invoking Function
  • A self-invoking expression is invoked (started) automatically, without being called
  • Function expressions will execute automatically if the expression is followed by ()
  • (function () {
      	var x = "Hello!!";  // I will invoke myself
    })();
    		
    var loop = function() { 
        for(var x = 0; x < 5; x++) {
           console.log(x); 
        } 
    }();
    
    		
    Arguments Object
    function f()
    {
    	if (arguments.length == 0) return 'undefined';
    
    	var min = arguments[0];
    
    	for(var i = 0; i < arguments.length; i++)
    		if (arguments[i] < min)
    			min = arguments[i];
    
    	return min;
    }
    
    console.log(f(-1, 0, 1, 2));
    		
    Rest Parameters
    function f(p1, ...params)
    {
    	console.log(p1);
    
    	for(let i = 0; i < params.length; i++)
    		console.log(params[i]);
    }
    
    f(1, 2, 3, 4)
    
    		
    call()
    var person = {
    	info: function () {return this.name + " : " + this.age;},
    	setName: function (n) {this.name = n;}
    }
    
    var person1 = {name: 'Lin', age: 39};
    var person2 = {name: 'Yanhua', age: 39};
    
    person.setName.call(person1, 'Yanhua');
    console.log(person.info.call(person1));
    console.log(person.info.call(person2));
    		
    apply()
  • The call() method takes arguments separately
  • The apply() method takes arguments as an array
  • var a = [1, 2, 3];
    
    console.log(Math.max.apply(null, a)); // apply Math.max() method to array
    		
    Closure
  • Is assigned the return value of a self-invoking function
  • It can access the counter in the parent scope
  • <button type="button" onclick="myFunction()">Count!</button>
    
    <p id="demo">0</p>
    
    <script>
    var add = (function () {
      var counter = 0;
      return function () {counter += 1; return counter;}
    })();
    
    function myFunction(){
      document.getElementById("demo").innerHTML = add();
    }
    </script>
    		
    Recursive
    const fact = (n) =>
    {
    	if (n == 1)
    		return n;
    	else
    		return n*fact(n-1);
    }
    
    console.log(fact(10));
    		
    Generator
    function* g(n)
    {
    	for(let i = 0; i < n; i++)
    		yield i;
    }
    
    for (e of g(10))
    	console.log(e);
    		
    Promises
  • Implement async programming in JavaScript
  • function divide (a, b)
    {
    	var p = new Promise(function(resolve, reject)
    		{
    			// do a thing, possibly async , then..
    			if(b == 0)
    				reject(Error("Denominator is Zero ..."));
    			else
    				resolve(a/b);
    		});
    
    	return p;
    }
    
    divide(10, 2).then(function(result)
    	{console.log("Result: "+result);},
    	function(error)
    	{console.log("Error: "+error);}
    );
    
    divide(6, 0).then(function(result)
    	{console.log("Result: "+result);},
    	function(error)
    	{console.log("Error: "+error);}
    );
    		
  • XMLHttpRequest
    1. request = new XMLHttpRequest(), synchronous and asynchronous
    2. request.open(method, URL, [async, user, password])
    3. xhr.send([body], GET do not have a body, POST use body to send the data to the server
    4. Listen to request events for response
      • load – when the request is complete (even if HTTP status is like 400 or 500), and the response is fully downloaded
      • error – when the request couldn’t be made
      • progress – triggers periodically while the response is being downloaded, reports how much has been downloaded
  • <!DOCTYPE html>
    <html lang="en">
    <head>
    	<meta charset="UTF-8">
    	<title>Document</title>
    </head>
    <body>
    	<script type="text/javascript">
    	const getFakeMembers = count => new Promise((resolves, rejects) => { 
    	const api = `https://api.randomuser.me/?nat=US&results=${count}` 
    	const request = new XMLHttpRequest()
    	request.open('GET', api)
    	request.onload = () =>
               (request.status === 200) ?
                resolves(JSON.parse(request.response).results) :
                reject(Error(request.statusText))
    	request.onerror = (err) => rejects(err)
    	request.onprogress = function(event) { // triggers periodically
      		console.log(`Received ${event.loaded} of ${event.total}`);};
    	request.send()
    })
    
     getFakeMembers(1).then(
          resolves = (members) => console.log(members),
          rejects = (err) => {
    	      console.error(new Error("cannot load members from randomuser.me"));
          		console.log(err)
          }
     )
    	</script>
    </body>
    </html>
    		
  • Chaining
  • var promise = job1();
    
    promise
    
    .then(function(data1) {
        console.log('data1', data1);
        return job2();
    })
    
    .then(function(data2) {
        console.log('data2', data2);
        return 'Hello world';
    })
    
    .then(function(data3) {
        console.log('data3', data3);
    });
    
    function job1() {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                resolve('result of job 1');
            }, 1000);
        });
    }
    
    function job2() {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                resolve('result of job 2');
            }, 1000);
        });
    }
    		
    Functional Programming
  • JavaScript is a functional language because its functions are first-class citizens
  • Functions can be saved, retrieved, or flow through applications just like variables
  • Declarative programming is a style of programming where applications are structured in a way that prioritizes describing what should happen over defining how it should happen
  • Immutability
  • let color_lawn = { 
    	title: "lawn",
    	color: "#00FF00",
    	rating: 0 
    }
    
    //mutable
    function rateColor(color, rating) { 
    	color.rating = rating
    	return color
    }
    
    console.log(rateColor(color_lawn, 5).rating); //5
    console.log(color_lawn.rating); //5
    
    //immutable
    function rateColor_2(color, rating){
    	return Object.assign({}, color, {rating:rating}) //Object.assign() merges all objects you pass it into the first one
    }
    
    console.log(rateColor_2(color_lawn, 10).rating); //10
    console.log(color_lawn.rating); //5
    
    //or arrow function with spread operator
    const rateColor_3 = (color, rating) => ({...color, rating})
    
    console.log(rateColor_3(color_lawn, 100).rating); //100
    console.log(color_lawn.rating); //5
    		
    let list=[
    	{ title: "Rad Red"}, 
    	{ title: "Lawn"},
    	{ title: "Party Pink"}
    ]
    
    //mutable
    var addColor = function(title, colors) { 
    	colors.push({ title: title })
    	return colors;
    }
    
    console.log(addColor("Glam Green", list).length); //4
    console.log(list.length); //4
    
    //immutable
    var addColor_3 = (title, colors) => colors.concat({title})
    
    console.log(addColor_3("Blue", list).length); //5
    console.log(list.length); //4
    
    //or with spread operator
    var addColor_2 = (title, colors) => [...colors, {title}]
    
    console.log(addColor_2("Red", list).length); //5
    console.log(list.length); //4
    
    		
  • Pure Function
  • const frederick = {
    	name: "Frederick Douglass", 
    	canRead: false,
    	canWrite: false
    }
    
    const selfEducate = person => ({
    	...person, 
    	canRead: true, 
    	canWrite: true
    })
        
    console.log( selfEducate(frederick) )
    console.log( frederick )
    
    // {name: "Frederick Douglass", canRead: true, canWrite: true}
    // {name: "Frederick Douglass", canRead: false, canWrite: false}
    		
  • Data Transformations
  • remove an item from an array we should use Array.filter over Array.pop or Array.splice because Array.filter is immutabl
  • const schools = [ "Yorktown", "Washington & Lee", "Wakefield"]
    
    const wSchools = schools.filter(school => school[0] === "W");
    console.log( wSchools ) 
    // ["Washington & Lee", "Wakefield"]
    		
    const schools = [ "Yorktown", "Washington & Lee", "Wakefield"]
    
    const highSchools = schools.map(school => `${school} High School`);
    console.log(highSchools.join("\n")
    //  Yorktown High School
    //  Washington & Lee High School
    //  Wakefield High School
    		
    const schools = [ "Yorktown", "Washington & Lee", "Wakefield"]
    
    const highSchools = schools.map(school => ({ name: school }));
    console.log( highSchools )
    // [
    //   { name: "Yorktown" },
    //   { name: "Washington & Lee" },
    //   { name: "Wakefield" }
    // ]
    		
  • higher-order functions
  • const createScream = logger => message => logger(message.toUpperCase() + "!!!");
    
    const scream = createScream(message => console.log(message));
    scream('functions can be returned from other functions')
    		
  • recursive
  • const countdown = (value, fn) => { 
    	fn(value)
    	return (value > 0) ? countdown(value-1, fn) : value 
    }
        
    countdown(10, value => console.log(value));
    		
  • Composition
  • const template = "hh:mm:ss tt"
    const clockTime = template.replace("hh", "03")
              .replace("mm", "33")
              .replace("ss", "33")
              .replace("tt", "PM")
    console.log(clockTime)
    		
    Helper Function
  • A helper function is a function help another function
  • function helper(num)
    {
    	return help(num+5);
    }
    
    function help(num)
    {
    	console.log(num);
    }
    
    helper(5);
    		
    Reference
  • Named and Optional Arguments in JavaScript
  • Explaining Value vs. Reference in Javascript