Javascript method Implementation
Tags: javascript, webdev, beginners, tutorial
Published: 2021-12-07 14:35:54

"Let's take a deep dive to the most basic javascript method implementation. Hope it will help you to understand the language better"</br>
</br>
</br>
</br>
</br>
</br>
**1. Object.create()**

> The Object.create() method creates a new object, using an existing object as the prototype of the newly created object.

```javascript
Object.prototype.newCreate = fucntion (obj) {
    // create a new function object as 
    function F(){}

    //bind the function object's prototype to the obj
    F.prototype = obj
    
    //return the newly created object based on F()
    return new F()
}
```

**2. instanceof**

> The instanceof operator tests to see if the prototype property of a constructor appears anywhere in the prototype chain of an object. The return value is a boolean value.

```javascript
function myInstanceOf (left, right) {
    //access left object's prototype chain
    let leftProto = left.__proto__
    //access right constructor's prototype method
    let rightProto = right.prototype
    
    //check if rightProto is on the left object's prototype chain
    while (leftProto) {
        if (leftProto === rightProto) return true
        else leftProto = leftProto.__proto__
    }
    return false
}
```

**3. new**

> The new operator lets developers create an instance of a user-defined object type or of one of the built-in object types that has a constructor function.

```javascript
function myNew (context, ...args) {
    //create a empty object 
    let obj = {}
    //link the new object's prototype chain to the constructor's prototype
    obj.__proto__ = context.prototype
    //call the constructor function on new object.
    let result = context.call(obj, ...args)
    return typeof result === "object" ? result : obj
}
```

**4. promise.all()**

> The Promise.all() method takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results of the input promises. This returned promise will resolve when all of the input's promises have resolved, or if the input iterable contains no promises. It rejects immediately upon any of the input promises rejecting or non-promises throwing an error, and will reject with this first rejection message / error.

```javascript
//takes in an array of promises
function myPromiseAll(arr){
    // return a new promise
    return new Promise(function (resolve,reject) {
        let len = arr.length
        // setup a array to record the result
        let result = []
        let resolvedCount = 0
        for (let i = 0; i < len; i++) {
           //wrap the value from array in case it is not a promise 
           Promise.resolve(arr[i]).then(function(value){
               result[i] = value
               //resolve the result when finish resolving everything 
               resolvedCount++
              if (resolvedCount === len) return resolve(result)
          }, function(error) {
             // if there is an error, reject immediately
             return reject(error)
          })
       }
  })
}
```


**5. promise.race()**

> The Promise.race() method returns a promise that fulfills or rejects as soon as one of the promises in an iterable fulfills or rejects, with the value or reason from that promise.

```javascript
//takes in an array of promises
function myPromiseRace(arr){
    return new Promise(function (resolve,reject) {
        for (let i = 0; i < arr.length; i++) { 
           Promise.resolve(arr[i]).then(resolve, reject})
       }
  })
}
```

**6. Debounce function**

> The debounce() function forces a function to wait a certain amount of time before running again. The function is built to limit the number of times a function is called.

```javascript
function debounce (func, delay) {
   // set a timer variable in the clousure to keep track
   let timer = null
   //return a debounced function
   return function debounced (...args) {
        //if timer is not null, clear the timer
        if (timer) {
                clearTimeout(timer)
                timer = null
            }
        //set a delay to run the function
        timer = setTimeout(()=> {
           func(...args)  
        }, delay)   
   }
}
```

**7. Throttle function**

>  To throttle a function means to ensure that the function is called at most once in a specified time period (for instance, once every 10 seconds). This means throttling will prevent a function from running if it has run “recently”. Throttling also ensures a function is run regularly at a fixed rate.

```javascript
function throttle (func, wait) {
    let timer = null
// set a flag in clousure to decide whether the current throttled program is running
    let flag = true

    return function throttled (...args) {
// if the flag is true, call the function and set the flag to false
        if (flag) {
            flag = false
            func(...args)
            timer = setTimeout(()=>{
            //set the flag back to true once finished waiting
                flag = true
                timer = null
            }, wait)
        }
    }
}
```

**8. Function.prototype.call()**

> The call() method calls a function with a given this value and arguments provided individually. 

Function.prototype.apply() is similar to call, we just need to change the seperate arguments to array.

```javascript
Function.prototype.newCall = function (context, ...args) {
   // this is pointing to the function that call this newCall method, when we assign this function as context's property, this will point to the context.
    context.fn = this
    let result =  context.fn(...args)
    delete context.fn    
    return result
}
```

**9. Function.prototype.bind()**

> The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

```javascript
Function.prototype.bind = function (context,...args) {
    let func = this
    //save the rest of the parameters
    return function binded (...rest) {
        //concat the arguments
        return func.call(context,...args,...rest)
    }
}
```


**10. a function to determine the type of an object**

> Using toString() to detect object class
> toString() can be used with every object and (by default) allows you to get its class.
> To use the Object.prototype.toString() with every object, you need to call Function.prototype.call() or Function.prototype.apply() on it, passing the object you want to inspect as the first parameter (called thisArg).

```javascript
function typeOf(obj) {
// use array destructuring to extract the result
    let [,result] = Object.prototype.toString.call(obj).split(" ")
//slice out unnecessary characters
    return result.slice(0,-1)
}
```

**11. curried function**

> Currying is an advanced technique of working with functions. It’s used not only in JavaScript, but in other languages as well.
> Currying is a transformation of functions that translates a function from callable as f(a, b, c) into callable as f(a)(b)(c).
> Currying doesn’t call a function. It just transforms it.

```javascript
function curry (func) {
    return function curried (...args) {
      //compare the current arguments length with the function's required parameters. 
        if (args.length >= func.length){
            return func(...args)
        } else {
            // concat the rest of the arguments
            return function (...rest) {
                return curried(...args,...rest)
            }
        }
    }
}
```

**12. AJAX request**

> AJAX update a web page without reloading the page
> Request data from a server - after the page has loaded
> Receive data from a server - after the page has loaded
> Send data to a server - in the background

```javascript
let url = "/server"

let xhr = new XMLHttpRequest();

xhr.open("GET", url, true)

xhr.onreadystatechange = function (){
// if readyState is 4 and status 200 means the request has been sucessfully executed. We can proceed to handle the response.
    if (this.readyState == 4 && this.status == 200) {
            handle(this.response)
        }
    }
}

xhr.onerror = function(){
    console.log(this.statusText)
}

xhr.send();
```

**wrap the ajax in a promise**

```javascript
function ajaxPromise (url) {
    return new Promise(function (resolve,reject) {
        let xhr = new XMLHttpRequest()
        xhr.open("GET", url, true)
        xhr.onreadystatechange = function () {
            if (this.readyState === 4 && this.status === 200) {
                return resolve(this.response)
            }
        }
        xhr.onerror = function(){
            return reject(this.statusText)
        }
        xhr.send()
    })
}
```

**13. Shallow Copy**

1. using slice

```javascript
let arr = [1,2,3,4];
console.log(arr.slice()); // [1,2,3,4]

```
2. use spread operator

```javascript
obj = {first: 1, 
       second: 2}
let cloneObj = { ...obj };
```

**14. Deep Copy**

1. handwritten deepcopy
```javascript
function deepCopy (obj) {
     let newObj = Array.isArray(obj) ? [] : {}
     
     for (key in obj) {
         newObj[key]=typeof obj[key]==="object"?deepCopy(obj[key]):obj[key]
     }
     
    return newObj
}
```
2. JSON.parse(JSON.stringify(obj))

But this method has a problem. If there are functions, undefined, and symbols in the copied object, they will disappear after processing with JSON.stringify().

**15. randomize the item sequence in array**

```javascript
function randomOutput(arr) {
    let len = arr.length
    for (let i = 0; i < len; i ++) {
        let randomNum = Math.floor(Math.random()*(len - i)) + i
        [arr[i], arr[randomNum]] = [arr[randomNum], arr[i]]
    }
    return arr
}
```

**16. How to flatten array**

recursively flatten the array use array reduce method
```javascript
function flatten (arr) {
    return arr.reduce((accum,element)=>{
        let flag = Array.isArray(element)
        return accum.concat(flag?flatten(element):element)
    },[])
}
```

**17. Event publisher and subscriber model**

this is not a complete implementation

```javascript
class EventEmitter {
    constructor () {
        this.events = {}
    }
    
    on (eventName, callbackFn) {
        if (!(eventName in this.events)) this.events[eventName] = []
        this.events[eventName].push(callbackFn)
    }
    
    emit (eventName, ...args) {
        this.events[eventName].forEach(fn => fn(...args))
    }
    
    off(eventName, callbackFn) {
        this.events[eventName] = this.events[eventName].filter(fn => fn != callbackFn && fn.initialCallback != callbackFn)
        if (this.events[eventName].length == 0) delete this.events[eventName]
    }
    
    once (eventName, callbackFn) {
        const one = (...args) => {
            callbackFn(...args)
            this.off(eventName, callbackFn)
        }
        one.initialCallback = callbackFn
        
        this.on(eventName, one)
    }
}
```


**18. Inherit from parent constructor**

```javascript
function Human (name,age) {
    this.name = name
    this.age = age
}

function Man (name,age) {
    Human.call(this,name,age)
}

Man.prototype = Object.create(Human.prototype)
Man.prototype.constructor = Man

```


**19.Convert Json to Tree**

```javascript
source = [{
            id: 1,
            pid: 0,
            name: 'body'
          }, {
            id: 2,
            pid: 1,
            name: 'title'
          }, {
            id: 3,
            pid: 2,
            name: 'div'
          }]

function toTree(src) {
    let map = {}
    src.forEach((ele)=>{
        map[ele["id"]] = ele
    })
    let result = []
    src.forEach((ele) => {
        let parent = map[ele.pid]
        if (parent) {
            if (!parent.children) parent.children = []
            parent.children.push(ele)
        } else {
            result.push(ele)
        }
    })


//Use React.createElement API

function tree(props){
  return React.createElement(props.name, props.props, props.children.map( child => tree(child)))
}
    return result
}
```


**20.Quick Sort**

```javascript
const quickSort1 = arr => {
	if (arr.length <= 1) {
		return arr;
	}
	//find the mid index
	const midIndex = Math.floor(arr.length / 2);
	//retrieve the mid index value
	const valArr = arr.splice(midIndex, 1);
	const midIndexVal = valArr[0];
	const left = []; //save those smaller than midIndexVal
	const right = []; //save those bigger than midIndexVal
	//iterate the array, push them into respective side. 
	for (let i = 0; i < arr.length; i++) {
		if (arr[i] < midIndexVal) {
			left.push(arr[i]); 
		} else {
			right.push(arr[i]); 
		}
	}
	//recursively sort the array until array length < 1
	return quickSort1(left).concat(midIndexVal, quickSort1(right));
};
const array2 = [5, 4, 3, 2, 1];
console.log('quickSort1 ', quickSort1(array2));
// quickSort1: [1, 2, 3, 4, 5]
```


**21.Merge Sort**
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z3u0umfadm8iawgiiibn.png)
 

**22.Create Element tree with react**

```javascript
function tree(props){
  return React.createElement(props.name, props.props, props.children.map( child => tree(child)))
}
```