debounce & throttle
2020-06-01Disclaimer
This article is originally based on my understanding of this concept. No guarantee on the accuracy.😅
Throttle
Throttle is used to limit how often a function can be called, though throttle is simpler to implement
Using a flag to record the state: within or exceed the time limit
Use case: during scrolling, resizing
1 | const throttle = (fn, limit) => { |
Debounce
A debounced function is called only once in a given period, delay milliseconds after its last invocation (the timer is reset on every call).
use case: auto search
1 | const debounce = (fn, limit) => { |
type conversion
2020-05-27Type Conversion
Primitive
JavaScript is a loosely typed or a dynamic language. Variables in JavaScript are not directly associated with any particular value type, and any variable can be assigned (and re-assigned) values of all types:
There are 6 primitive data types: string, number, bigint, boolean, undefined, and symbol.
There also is null, which is seemingly primitive, but indeed is a special case for every Object: and any structured type is derived from null by the Prototype Chain.
Except for null and undefined, all primitive values have object equivalents that wrap around the primitive values:
String/ Number /BigInt /Boolean / Symbol
The wrapper’s valueOf() method returns the primitive value.
Explicit coercion
![type converting](type-conversion/type converting.png)
Boolean()
Primitive to Boolean
1 | console.log(Boolean()) // false |
Number()
When Number is called as a function rather than as a constructor, it performs a type conversion.
Returns a Number value (not a Number object) computed by ToNumber(value)
if value was supplied, else returns +0.
toNumber()
Type | Result |
---|---|
Undefined | NaN |
Null | +0 |
Boolean | true value-> 1 false value-> +0 |
Number | same number |
String |
1 | console.log(Number()) // +0 |
1 | console.log(parseInt("3 abc")) // 3 |
String()
When String
is called as a function rather than as a constructor, it performs a type conversion.
Returns a String value (not a String object) computed by ToString(value)
. If value is not supplied, the empty String “” is returned.
toString()
Type | Result |
---|---|
Undefined | “undefined” |
Null | “null” |
Boolean | true value-> “true” false value ->”false” |
Number | |
String | Same |
1 | console.log(String()) // 'empty string' |
Primitive type to reference type
String()、Number() and Boolean() constructor with new
keyword
1 | var a = 1; |
primitive to boolean
1 | console.log(Boolean(new Boolean(false))) // true |
Argument Type | Result |
---|---|
Undefined | Throw a TypeError exception. |
Null | Throw a TypeError exception. |
Object to string and number
first converts to primitive using toPrimitive, then convert to sting/number using ToString/ToNumber
Object.prototype
{
toString: ƒ toString()
valueOf: ƒ valueOf()
….
}let a ={}
a.valueOf= function(){ return ‘run this method’}
1 | let a ={a:'1'} |
1 | console.log(({}).toString()) // [object Object] |
Implicit coercion
(👆The tricky part)
Abstract Equality Comparison (==
)
Operand B | |||||||
---|---|---|---|---|---|---|---|
Undefined | Null | Number | String | Boolean | Object | ||
Operand A | Undefined | true |
true |
false |
false |
false |
false |
Null | true |
true |
false |
false |
false |
false |
|
Number | false |
false |
A === B |
A === ToNumber(B) |
A === ToNumber(B) |
A == ToPrimitive(B) |
|
String | false |
false |
ToNumber(A) === B |
A === B |
ToNumber(A) === ToNumber(B) |
A == ToPrimitive(B) |
|
Boolean | false |
false |
ToNumber(A) === B |
ToNumber(A) === ToNumber(B) |
A === B |
ToNumber(A) == ToPrimitive(B) |
|
Object | false |
false |
ToPrimitive(A) == B |
ToPrimitive(A) == B |
ToPrimitive(A) == ToNumber(B) |
A === B |
To primitive:
ToPrimitive(A)
attempts to convert its object argument to a primitive value, by attempting to invoke varying sequences of A.toString
and A.valueOf
methods on A
.
the piority of comparison type is
Number > String >Boolean>Obj
if one side is number, then convert to number; else if one side is boolean, convert to number
true=='2'//false true->Number ->1 '2'->Number ->2 false=='a'//false true='a'//false 'a'->Number->NaN <!--8-->
1 | [] == ![] //true |
‘+’ operartor
1 | var a = 21; |
|| && !
The value produced by a &&
or ||
operator is not necessarily of type Boolean. The value produced will always be the value of one of the two operand expressions.
1 | let A = ''; |
Ref:
Binary tree part 1
2020-05-27Disclaimer
This article is originally based on my understanding of this concept. No guarantee on the accuracy.😅
Since the root and node share similar structure, it’s natural to use recursion to solve relative problem.
Also, iteration can also be applied. The key would be which kind of data structure to store the data of a tree. Normally, a queue(FIFO) or a stack(FILO) depeding on the traversal order.
Binary Tree in javascript:
1 | function BinaryTree() { |
Or using an array to store the elements of the tree where the root node is stored at index 1 not 0.
For complete binary tree, if the index of an element (eg, D, i = 4). Its left child node will be stored in 2*i
(H,at 8), and its right childe node will be stored in2 * i-1
, its root node will be stored at Math.floor( i/2)
Traversal of tree
Depth-first | Breath-first |
---|---|
Preorder | Level-order |
Inorder | |
Postorder |
Preorder (root -> left node ->right node
Recursion:
1 | var preorderTraversal = function (root) { |
*Iteration: *
version 1:
1 | const preorderTraversal = (root) => { |
version 2:
1 | var preorderTraversal = function (root) { |
Inorder left node -> root -> right node
-
Recursion:
1 | var inorderTraversal = function (root) { |
A visual way to understand inheritance & prototype
2020-05-25A visual way to understand inheritance & prototype
Disclaimer
This article is originally based on my understanding of this concept. No guarantee on the accuracy.😅
In JavaScript, there is actually no concept of real Class (in es6, class is purely syntax sugar 🍬)
The inheritance was made by inheriting along the prototype chain. And it’s a real OOP language since you can create a new object directly from an object bypassing the class.
The keyword new <Constructor>
and Object.create(<Prototype object>
) method can both manuiplate the prototype chain (__proto__
):
the orange line refers to the prototype chain.
1 | function A(argu){ |
the new keyword and the .create method both combine the returned object to the prototype of the constructor function. However, the new object a2 will inheritage the this.con property constructor (a function) while the a1 will not.
Both a1 and a2 have access to the .proto method by searching along the prototype chain.
A common mistakes when I first bump into the idea of inheritance I have made was accidentally create an object from a constructor function rather than the prototype of the constructor.
As the figure shown, the incorrectly created object a1now is an instance of function. And have no access to method of A.prototype.proto:
1 | a1 instanceof Function //true |
The prototype object can be only found on a function. An object other than function have no pointer referencing to prototype.
Leetcode Linked List
2020-05-24Linked List
Disclaimer
This article is originally based on my understanding of this concept. No guarantee on the accuracy.😅
Comparing with Array, linked list dosen’t support accessing by index. So for searching a certain element, the complexcity is O(n).
The linked list doesn’t took up continuous space in memory, so for inserting/deleting element, the complexcity is O(1)
Using two pointer can help to reduce the complexity.
For loop in the list, using fast and slow pointers.
206. Reverse Linked List
Reverse a singly linked list.
Example:
Input: 1->2->3->4->5->NULL
Output: 5->4->3->2->1->NULL
Follow up:
A linked list can be reversed either iteratively or recursively. Could you implement both?
iterative
1
2
3
4
5
6
7
8
9
10
11
12
13var reverseList = function (head) {
if (!head || !head.next) return head;
let pre = null,
cur = head;
while (cur) {
let next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
head = pre;
return head;
};recursive
1
2
3
4
5
6
7
8var reverseList = function (head) {
if (!head || !head.next) return head;
let next = head.next;
let reversedHead = reverseList(next);
head.next = null;
next.next = head;
return reversedHead;
};
21. Merge Two Sorted Lists
Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.
Example:
Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4
- iterative (two pointer)
1 | var mergeTwoLists = function (l1, l2) { |
Recursive
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16function mergeTwoLists(l1, l2) { //always compare two node
if(l1 === null) { //if it reaches the end return the other node
return l2
}
if(l2 === null) {
return l1
}
if(l1.val <= l2.val) {
l1.next = mergeTwoLists(l1.next, l2) //let the next head point to the next result
//pass the new head l1.next
return l1 //return the smaller one
} else {
l2.next = mergeTwoLists(l2.next, l1) //pass the new head l2.next
return l2
}
}
160. Intersection of Two Linked Lists
Write a program to find the node at which the intersection of two singly linked lists begins.
Input: intersectVal = 8,
listA = [4,1,8,4,5],
listB = [5,0,1,8,4,5],
skipA = 2, skipB = 3Output: Reference of the node with value = 8
Input Explanation: The intersected node’s value is 8 (note that this must not be 0 if the two lists intersect). From the head of A, it reads as [4,1,8,4,5]. From the head of B, it reads as [5,0,1,8,4,5]. There are 2 nodes before the intersected node in A; There are 3 nodes before the intersected node in B.
Input: intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
Output: Reference of the node with value = 2
Input Explanation: The intersected node’s value is 2 (note that this must not be 0 if the two lists intersect). From the head of A, it reads as [0,9,1,2,4]. From the head of B, it reads as [3,2,4]. There are 3 nodes before the intersected node in A; There are 1 node before the intersected node in B.
Input: intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
Output: null
Input Explanation: From the head of A, it reads as [2,6,4]. From the head of B, it reads as [1,5]. Since the two lists do not intersect, intersectVal must be 0, while skipA and skipB can be arbitrary values.
Explanation: The two lists do not intersect, so return null.
1 | var getIntersectionNode = function (headA, headB) { |
141. Linked List Cycle
Given a linked list, determine if it has a cycle in it.
To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.
Example 1:
Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the second node.
Example 2:
Input: head = [1,2], pos = 0
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the first node.
Example 3:
Input: head = [1], pos = -1
Output: false
Explanation: There is no cycle in the linked list.
Follow up: Can you solve it using O(1) (i.e. constant) memory?
Use slow & fast pointers:
Space complexity :O(1) Time complexcity: O(n)
1 | var hasCycle = function(head) { |
Using the list to store a marker/flag to indicate if this node was traversed.
Space&Time complexcity: O(N)
1 | var hasCycle = function(head) { |
234. Palindrome Linked List
Given a singly linked list, determine if it is a palindrome.
Example 1:
Input: 1->2
Output: false
Example 2:
Input: 1->2->2->1
Output: true
Follow up: Could you do it in O(n) time and O(1) space?
Two pointer:
1 | var isPalindrome = function (head) { |
Using stack:
1 | var isPalindrome = function (head) { |
148. Sort List
Sort a linked list in O(n log n) time using constant space complexity.
Example 1:
Input: 4->2->1->3
Output: 1->2->3->4
Example 2:
Input: -1->5->3->4->0
Output: -1->0->3->4->5
Merge sorting:
It’s easy to just apply the Divided Conqure algorithm template 😁