js 算法

复杂度

通常采用大 O 表示法来表示复杂度。它并不代表真正的执行时间或存储空间消耗,而是表示代码执行时间随数据规模增长的变化趋势(时间复杂度)或存储空间随数据规模增长的变化趋势(空间复杂度),所以,也叫作渐进时间(或空间)复杂度(asymptotic time complexity),简称时间(或空间)复杂度。

常见复杂度

o(N)

function test(num) {
  let total = 0
  for(let i =0;i<num;i++) {
      total +=i
  }
  return total
}
console.log(test(100));

O(1)


function test(num) {
  let i= num
  let j = 2*num
  return i+j
}
console.log(test(100));

O(logN)


function test(num) {
  let i= 1
  while(i <num) {
      i = i*2
  }
  return i
}
console.log(test(100));

O(M+N)

function test(num1,num2) {
  let total = 0
  for(let i =0;i<num1;i++) {
      total += i
  }
  for(let j =0;j<num2;j++) {
      total +=j
  }
  return total

}
console.log(test(100,90));

o(n*logn)


function test(num1,num2) {
  let total =0;
  let j =0;
  for(let i=0;i<num1;i++) {
      while(j <num2) {
          total = i + j
          j = j+2;
      }
  }
  return total

}
console.log(test(10,100));

多项式量级:

常量阶:O(1):当算法中不存在循环语句、递归语句,即使有成千上万行的代码,其时间复杂度也是Ο(1)

对数阶:O(logn): 简单介绍一下


let i=1;
while (i <= n)  {
  i = i * 2;
}
  • 每次循环 i 都乘以 2 ,直至 i > n ,即执行过程是:20、21、22、…、2k、…、2x、 n 所以总执行次数 x ,可以写成 2x = n ,则时间复杂度为 O(log2n) 。这里是 2 ,也可以是其他常量 k ,时间复杂度也是:O(log~3~n) = O(log32 * log2n) = O(log2n)

  • 线性阶:O(n)

  • 线性对数阶:O(nlogn)

  • 平方阶、立方阶、….、k次方阶:O(n2)、O(n3)、…、O(nk)

非多项式量级

  • 指数阶:O(2n)

  • 阶乘阶:O(n!)

复杂度的划分最好时间复杂度:在最理想的情况下,执行这段代码的时间复杂度最坏时间复杂度:在最糟糕的情况下,执行这段代码的时间复杂度平均时间复杂度:所有情况下,求一个平均值,可以省略掉系数、低阶、常量

数组

优点:随机访问,可以通过下标随机访问数组中的任意位置上的数据

缺点:对数据的删除和插入不是很友好

查找:根据下标随机访问的时间复杂度为 O(1)

插入或者删除:时间复杂度为 O(n)在 JavaScript 中的数组几乎是万能的,它不光可以作为一个普通的数组使用,可以作为栈或队列使用

广度优先遍历


  let obj = {
      a: 1,
      b: 2,
      c: {
          e: 3,
          f: 4
      },
      g: null,
      h: [8, 9, 10],
      name: 'test',
      i: { j: 1, k: 2 }
  }
  function copy(obj) {
      let bfs = function (obj) {
          let queue = [obj], target = {}, list = [target]
          while (queue.length != 0) {
              let item = queue.shift()
              let temp = list.shift()
              for (const key in item) {
                  if (typeof item[key] === "object" && typeof item[key] != null) {
                      queue.push(item[key])
                      temp[key] = Array.isArray(item[key]) ? [] : {}
                      list.push(temp[key])
                  } else {
                      temp[key] = item[key]
                  }
              }
          }
          return target;
      }
      return bfs(obj)
  }
  let result = copy(obj)
  result.g = 3;
  console.log(obj)
  console.log(result)

 

全排列BFS


    function permute(nums) {
          const list = []
          backTrack(list, [], nums)
          return list
      }

      function backTrack(list, templist, nums) {
          if (templist.length === nums.length) {
              list.push(templist.slice(0))
          } else {
              for (let i = 0; i < nums.length; i++) {
                  if (templist.includes(nums[i])) {
                      continue
                  }
                  templist.push(nums[i])
                  backTrack(list, templist, nums)
                  templist.pop()
              }
          }
      }
      let array = [1, 2, 3]
      console.log(permute(array));

 

二分查找


var arr = [1, 8, 9, 12, 22, 28, 32, 44];
function binarySearch(target) {
  var start = 0, end = arr.length - 1, element, middle;
  while (start <= end) {
      middle = start + Math.floor((end - start) /2)
      element = arr[middle]
      if(target === element) {
          return middle
      } else if(target > element) {
          start = middle + 1
      } else if(target < element){
          end = middle - 1
      }
  }
  return -1
}
console.log(binarySearch(28));

无重复最长子串


      let s = "abcabcbb"
      function longestSubString (str) {
          let sub = []
          let max = 0
          for(let i =0;i<str.length;i++) {
              let index = sub.indexOf(str[i])
              if(index === -1) {
                  sub.push(str[i])
              } else {
                  sub = sub.slice(index + 1,sub.length)
                  sub.push(s[i])
              }
              max = Math.max(max,sub.length)
          }
          return max
      }
      console.log(longestSubString(s))

删除数组中部分元素


    function pull(arr, ...args) {
          const result = []
          for (let i = 0; i < arr.length; i++) {
              let item = arr[i]
              if (args.includes(item)) {
                  result.push(item)
                  arr.splice(i, 1)
                  i--
              }

          }
          return result
      }

      function pullAll(arr1,arr2) {
          return pull(arr1,...arr2)
      }
      let array = [1, 2, 3, 4, 5, 6, 8]
      // console.log(pull(array,2,3))
      console.log(pullAll(array,[1,3,4]))
      console.log(array)

 

数组去重


  let array = [1,2,2,2,3,4,3,1,1,2]
            let set = new Set(array)
            console.log([...set])

        let array = [1,2,2,2,3,4,3,1,1,2]
        function unique(array) {
          return array.filter((item,index,array)=>{
              return array.indexOf(item) === index
          })
        }  
        console.log(unique(array))

        let array = [1,2,2,2,3,4,3,1,1,2]
        function unique(array) {
          let result = []
          array.forEach(element => {
              if(result.indexOf(element) === -1) {
                  result.push(element)
              }
          });
          return result
        }  
        console.log(unique(array))

        let array = [1,2,2,2,3,4,3,1,1,2]
        function unique(array) {
          let result = []
          const obj = {}
          array.forEach(element => {
              if(!obj[element]) {
                  obj[element] = true
                  result.push(element)  
              }
          });
          return result
        }  
        console.log(unique(array))

字符串反转


      function reverseString(strIn, pos, strOut) {
          if(pos < 0) {
              return strOut
          }
          strOut += strIn.charAt(pos--)
          return reverseString(strIn,pos,strOut)
      }

      let str = "Hello World"
      let pos = str.length - 1
      let result = ''
      console.log(reverseString(str, pos, result))

    function reverseString(str) {
        let arr = Array.prototype.slice.call(str)
        return arr.reverse().join('')
      }

      let str = "Hello World"
   
      console.log(reverseString(str))

  function reverseString(str) {
      return str.split("").reverse().join("")
  }

  let str = "Hello World"
  console.log(reverseString(str))

    function reverseString(str) {
        let result = []
        let array = str.split("")
        while(array.length) {
            result.push(array.pop())
        }
        return result.join("")
  }

  let str = "Hello World"
  console.log(reverseString(str))

字符串截取


      function truncate(str,size) {
      return str.length > num ? str.slice(0, num) + '...' : str
      }
      let str = "Hello World"
      console.log(truncate(str,2))

 

字符串出现最多的字符


function getMaxCount(str) {
      let maxCount = 0
      let maxCountChar = ''
      let json = {}
      for(let i =0;i<str.length;i++) {
          let char = str[i]
          if(json[char]) {
              json[char]++
          } else {
              json[char] = 1
          }
      }
      for(let key in json) {
          if(json[key] > maxCount) {
              maxCount = json[key]
              maxCountChar = key
          }
      }
      return maxCount
  }
  console.log(getMaxCount("helloworldddd"))

 


  function getMaxCount(str) {
      let maxCount = 0
      let maxCountChar = ''
      while(str) {
          let char = str[0]
          let length = str.length
          let reg = new RegExp(char,'g')
          str = str.replace(reg,'')
          let restLength = str.length
          let charCount = length - restLength
          if(charCount > maxCount) {
              maxCount = charCount
              maxCountChar = char
          }
      }
      return maxCount
  }
  console.log(getMaxCount("helloworldddd"))

  function getMaxCount(str) {
      let maxCount = 0
      let maxCountChar = ''
      str = str.split('').sort().join('')
      for(let i =0,j= str.length;i<j;i++) {
          let char = str[i]
          let charCount = str.lastIndexOf(char) - i + 1
          if(charCount > maxCount) {
              maxCount = charCount
              maxCountChar =char
          }
          i = str.lastIndexOf(char)
      }
      return maxCount
  }
  console.log(getMaxCount("helloworldddd"))

 

去除字符串中重复字符


  function removeDuplicateChar(str) {
      let result = ''
      for(let i =0;i<str.length;i++) {
          if(result.indexOf(str[i]) < 0) {
              result+=str[i]
          }
      }
      return result
  }
  console.log(removeDuplicateChar("helloworld"))

  function removeDuplicateChar(str) {
      let result = ''
      let json = {}
      for(let i =0;i<str.length;i++) {
          let char = str[i]
          if(!json[char]) {
              result +=char
              json[char] = true
          }  
      }
      return result
  }
  console.log(removeDuplicateChar("helloworld"))

  function removeDuplicateChar(str) {
      let array = str.split('')
      let newArray = array.filter((item,index,array)=>{
          return array.indexOf(item) === index
      })
      return newArray.join('')
  }
  console.log(removeDuplicateChar("helloworld"))

  function removeDuplicateChar(str) {
      let newArray = Array.prototype.filter.call(str,(item,index,array)=>{
          return array.indexOf(item) === index
      })
      return newArray.join('')
  }
  console.log(removeDuplicateChar("helloworld"))

  function removeDuplicateChar(str) {
      let set = new Set(str.split(''))
      return [...set].join('')
  }
  console.log(removeDuplicateChar("helloworld"))

 

素数


        let isPrime = function(number) {
            if(number === 2) {
                return true
            }
            let square = Math.sqrt(number)
            for(let i =2;i<=square;i++) {
              if(number % i === 0) {
                  return false
              }
            }
            return true
        }

 

合并对象


    function mergeObject(...objs) {
          const result = {}
          objs.forEach(obj=>{
              Object.keys(obj).forEach(key=>{
                  if(result.hasOwnProperty(key)) {
                      result[key] = [].concat(result[key],obj[key])
                  } else {
                      result[key] = obj[key]
                  }
              })
          })
          return result
      }
      const object = {
          a: [{ x: 2 }, { y: 4 }],
          b: 1,
          c:"bar"
      }
      const other = {
          a: { z: 3 },
          b: [2, 3],
          c: 'foo'
      }
      console.log(mergeObject(object, other))

 

重复字符串

        function repeat(target,n) {
            if(n === 1) {
                return target
            }
           return [].concat([target],repeat(target,n-1))
        }
        let str = repeat('abc',4).join('')
        console.log(str)


        function repeat(target,n) {
            return Array(n+1).join(target)
        }
        let str = repeat('abc',4)
        console.log(str)


        function repeat(target,n) {
          return Array.prototype.join.call({length:n+1},target)
        }
        let str = repeat('abc',4)
        console.log(str)


       let str = "abc"
       console.log(str.repeat(4))


 

字符串回文

        function palindrome(str) {
            return reverseStr(str) === str
        }
        function reverseStr(str) {
            let array = [...str]
            return array.reverse().join("")
        }

        let str = "HeeH"
        console.log(palindrome(str))


        function isPalindromeStr(str) {
            if(!str.length) return true
            str = str.toLowerCase().split('')
            let start = 0
            let end = str.length - 1
            while(start < end) {
                if(str[start] === str[end]) {
                    start++
                    end--
                } else {
                    return false
                }
            }
            return true
        }
        // let str ="abcdcba"
        let str ="abcdcbag"
        console.log(isPalindromeStr(str))


        function isPalindromeStr(str) {
            if (str.length <= 1) {
                return true
            }
            str = str.toLowerCase()
            let startValue = str[0]
            let endValue = str[str.length - 1]
            if (startValue === endValue) {
                return isPalindromeStr(str.slice(1, str.length - 1))
            } else {
                return false
            }
        }
        // let str = "abcdcba"
          let str ="abcdcbag"
        console.log(isPalindromeStr(str))


 

生成测试数据

       let array = [...Array(100).keys()].map((i,index)=>index + 1)
       let array1 = Array.from(Array(100),(i,index)=>index+1)
       console.log(array)
       console.log(array1)


 

数组扁平化

       let array = [1, 2, 3, [4, 5], [6, 7, 8]]
        function flattern(arr) {
            var result = []
            for (let i = 0; i < arr.length; i++) {
                if (Array.isArray(arr[i])) {
                    result = result.concat(flattern(arr[i]))
                } else {
                    result.push(arr[i])
                }
            }
            return result
        }


        let array = [1, 2, 3, [4, 5], [6, 7, 8, [9, 10]]]
        function flattern(arr) {
            while(arr.some(item=>Array.isArray(item))) {
                arr = [].concat(...arr)
            }
            return arr
        }
        console.log(flattern(array))


        let array = [1, 2, 3, [4, 5], [6, 7, 8, [9, 10]]]
        function flattern(arr) {
            arr = arr.toString().split(",")
            var result = arr.map(item=>{
                return Number(item)
            })
            return result
        }
        console.log(flattern(array))


let arr = [1, [2, [3, 4]]];
function flatten(arr) {
    return arr.reduce(function(prev, next){
        return prev.concat(Array.isArray(next) ? flatten(next) : next)
    }, [])
}
console.log(flatten(arr));//  [1, 2, 3, 4,5]


let arr = [1, [2, [3, [4, 5]]], 6];
function flatten(arr) {
  let str = JSON.stringify(arr);
  str = str.replace(/(\[|\])/g, '');
  str = '[' + str + ']';
  return JSON.parse(str); 
}
console.log(flatten(arr)); //  [1, 2, 3, 4,5]



concat

        let array = [1,2,4]
        function concat(array,...args) {
            const result =[...array]
            args.forEach(item => {
                if(Array.isArray(item)) {
                    result.push(...item)
                } else {
                    result.push(item)
                }
            });
            return result
        }
        console.log(concat(array,[7,5,6],9,10))


 

数组map

        const array = [1,2,3,4,4,5]
        function map(arr,callback) {
            let result = []
            for(let i=0;i<arr.length;i++) {
                result.push(callback(arr[i])) 
            }
            return  result;
        }


        const result = map(array,item=>{
            return item*10
        })
        console.log(result)


数组find

let array = [1,2,1002,111]
    function find(array,callback) {
        for(let i =0;i<array.length;i++) {
            let res= callback(array[i],i)
            if(res) {
                return  array[i]
            }
        }
        return undefined
    }
    console.log(find(array,item=>item>1000))


数组some

        let array =[1,2,3,4,5,3,7]
        function some(array,callback) {
            for(let i=0;i<array.length;i++) {
                if(callback(array[i])) {
                    return true
                }
            }
            return false
        }
        console.log(some(array, (item)=>{
            return item > 5
        }))


数组every

        let array = [1, 2, 3, 4, 5, 3, 7]
        function every(array, callback) {
   
            for (let i = 0;i<array.length; i++) {
                if(!callback(array[i])) {
                     return false
                }
            }
            return true
        }
        console.log(every(array, (item)=>{
            return item > 10
        }))


数组reduce

        function reduce(array,callback,initValue) {
            let result = initValue
            for(let i =0;i<array.length;i++) {
               result = callback(result,array[i])
            }
            return result
        }
        let array = [1,2,3,4,5]
        let result = reduce(array,function(res,value){
            return res + value
        },10)
        console.log(result)


 

数组filter

      let array = [1,3,4,5,5,6]
        function filter(array,callback) {
            let result =[]
            for(let i =0;i<array.length;i++) {
                let res = callback(array[i])
                if(res) {
                    result.push(array[i])
                }
            }
            return result
        }
        let result = filter(array,item=>item%2 === 0)
        console.log(result)


 

数组slice

export function slice (array, begin, end) {
  // 如果当前数组是[], 直接返回[]
  if (array.length === 0) {
    return []
  }

  // 如果begin超过最大下标, 直接返回[]
  begin = begin || 0
  if (begin >= array.length) {
    return []
  }

  // 如果end不大于begin, 直接返回[]
  end = end || array.length
  if (end > array.length) {
    end = array.length
  }
  if (end <= begin) {
    return []
  }

  // 取出下标在[begin, end)区间的元素, 并保存到最终的数组中
  const arr = []
  for (let index = begin; index < end; index++) {
    arr.push(array[index])
  }

  return arr
}


数字出现的次数

     function keywordCount(arr) {
        let result = arr.reduce(function(pre,cur) {
            if(!pre[cur]) {
                pre[cur] = 1
            } else {
                pre[cur]++
            }
            return pre
         },{})
         return result
     }
     let c = [1,2,3,2,2,5,1]
     console.log(keywordCount(c))


获取数组中部分元素

        function drop(array,size =1) {
           return array.filter((item,index)=>index >= size)
        }
        let array =[1,2,3,4,5]
        console.log(drop(array,2))


 

删除数组中部分元素

        function pull(arr, ...args) {
            const result = []
            for (let i = 0; i < arr.length; i++) {
                let item = arr[i]
                if (args.includes(item)) {
                    result.push(item)
                    arr.splice(i, 1)
                    i--
                }

            }
            return result
        }

        function pullAll(arr1,arr2) {
            return pull(arr1,...arr2)
        }
        let array = [1, 2, 3, 4, 5, 6, 8]
        // console.log(pull(array,2,3))
        console.log(pullAll(array,[1,3,4]))
        console.log(array)


数组trunk

     function split(item,num) {
            if(item.length <=0) {
                return item
            }
            let groupSize = Math.ceil(item.length / num)
            return chunk(item,groupSize)
        }
        function chunk(item,size) {
            if(item.length <=0 || size <=0) {
                return item
            }
            let chunks = []
            for(let i =0;i<item.length;i+=size) {
                chunks.push(item.slice(i,i+size))
            }
            return chunks
        }

        let array = [1,2,3,4,4,5,5,6,5,56,6565,6,566,5,56,65,5665,56,222]
        console.log(split(array,6))


     function chunk(arr,size = 1) {
            if(arr.length === 0) {
                return []
            }
            let result =[]
            let tmp = []
            arr.forEach(item => {
                if(tmp.length === 0) {
                    result.push(tmp)
                }
                tmp.push(item)
                if(tmp.length === size) {
                    tmp =[]
                }
            });
            return result
        }
        let array = [1,2,3,4,4,5,5,6,5,56,6565,6,566,5,56,65,5665,56,222]
        console.log(chunk(array,6))


数组差异化

  function difference(arr1,arr2) {
            if(arr1.length === 0) {
                return []
            }
            if(arr2.length === 0) {
                return arr1
            }
            return arr1.filter(item => !arr2.includes(item))
        }

        let arr1= [1,3,4]
        let arr2 =[2,5,6,1]
        console.log(difference(arr1,arr2))


 

数组转tree

      const arr = [
            { id: 1, parentId: null, name: 'a' },
            { id: 2, parentId: null, name: 'b' },
            { id: 3, parentId: 1, name: 'c' },
            { id: 4, parentId: 2, name: 'd' },
            { id: 5, parentId: 1, name: 'e' },
            { id: 6, parentId: 3, name: 'f' },
            { id: 7, parentId: 4, name: 'g' },
            { id: 8, parentId: 7, name: 'h' },
        ]
        function array2Tree(array) {
            const result = []
            const map = array.reduce((pre,cur)=>{
                pre[cur.id] = cur
                return pre
            },{})
            for(let item of array) {
                if(item.parentId === null) {
                    result.push(item)
                    continue
                }
                if(item.parentId in map) {
                    const parent = map[item.parentId]
                    parent.children = parent.children || []
                    parent.children.push(item)
                }
            }
            return result
        }

       console.log(array2Tree(arr)) 


tree转array

        const data = [{
            "id": 1, "parentId": null, "name": "a",
            "children": [{
                "id": 3, "parentId": 1, "name": "c",
                "children": [{ "id": 6, "parentId": 3, "name": "f" }]
            },
            { "id": 5, "parentId": 1, "name": "e" }]
        },
        {
            "id": 2, "parentId": null, "name": "b",
            "children": [{
                "id": 4, "parentId": 2, "name": "d",
                "children": [{
                    "id": 7, "parentId": 4, "name": "g",
                    "children": [{ "id": 8, "parentId": 7, "name": "h" }]
                }]
            }]
        }]
        function flattern(array) {
            return array.reduce((pre,cur)=>{
                const {id,name,parentId,children = []} = cur
                return pre.concat([{id,name,parentId}],flattern(children))
            },[])
        }

        console.log(flattern(data))


获取数组中元素最小值和最大值

       Array.prototype.min = function() {
          let min = this[0]
          let len = this.length
          for(let i=1;i<len;i++) {
              if(this[i] < min) {
                  min = this[i]
              }
          }
          return min
       }
       Array.prototype.max = function() {
          let max = this[0]
          let len = this.length
          for(let i=1;i<len;i++) {
              if(this[i] > max) {
                  max = this[i]
              }
          }
          return max
       }
       let array = [2,10,6,8,7,1,88]

       console.log(array.min(),array.max())


       Array.prototype.min = function() {
          return Math.min.apply(null,this)
       }
       Array.prototype.max = function() {
          return Math.max.apply(null,this)
       }
       let array = [2,10,6,8,7,1,88]

       console.log(array.min(),array.max())


        Array.prototype.min = function () {
           return this.reduce((pre, cur) => {
                const result = pre > cur ? cur : pre
                return result
            })
        }
        Array.prototype.max = function () {
           return this.reduce((pre, cur) => {
                const result = pre < cur ? cur : pre
                return result
            })
        }
        let array = [2, 10, 6, 8, 7, 1, 88]

        console.log(array.min(), array.max())


        let array = [2, 10, 6, 8, 7, 1, 88]
        const sort = array.sort((a,b)=> a-b)
        console.log(sort)


 
        let array = [2, 10, 6, 8, 7, 1, 88]
      
        console.log(Math.min(...array),Math.max(...array))


数字千分化

        function thousandNum(number = 0) {
            const arr = (+number).toString().split('.')
            const intNum = arr[0]
            const floatNum = arr[1]
            const getInt = (nums) => {
               return   nums.split('').reverse().reduceRight((t, v, i) => {
                   let result =t + (i % 3 ? v : `${v},`)
                    return result
                }, '').replace(/^,|,$/g, '')
            }
            const getFloat = (nums) => {
              return  nums.split('').reduce((t, v, i) => {
                    return t + ((i + 1) % 3 ? v : `${v},`)
                }, '').replace(/^,|,$/g, '')
            }
            return arr.length > 1 ? `${getInt(intNum)}.${getFloat(floatNum)}` : `${getInt(intNum)}`
        }

        console.log(thousandNum(1234.5678))


apply

        function apply(fn, obj, args) {
            if (obj === null || obj === undefined) {
                obj = window
            }
            obj.tempFn = fn;
            const result = obj.tempFn(...args)
            delete obj.tempFn
            return result
        }
        var m = 11
        function f(a, b) {
            console.log(a, b, this.m, this)
            return a + b
        }

        const obj = { m: 22 }
        console.log(apply(f, obj, [1, 2, 3]))


// Function.prototype.myApply = function(context,args) {
//     context = context || window;
//     args = args ? args : []
//     const key = Symbol()
//     context[key] = this;
//     const result =context[key](...args)
//     delete context[key]
//     return result;
// }

//  let map = {}
//  map["1"] = ["1","2","3"]
//  map["2"] = ["4","5","6"]
//  map["3"] = ["7","8","9"]
// array.set("1",["1","2","3"])
// array.set("2",["4","5","6"])
// array.set("3",["7","8","9"])

// let array1  = [...array.get("1") , ...array.get("2"),...array.get("3")]
// console.log(array.keys().length)
// console.log(array1)


// console.log(Object.keys(map).length)




 

bind

  function call(fn, obj, ...args) {
            if (obj === null || obj === undefined) {
                obj = window
            }
            obj.tempFn = fn
            const result = obj.tempFn(...args)
            delete obj.tempFn
            return result
        }

        function bind(fn, obj, ...args) {
            console.log("bind")
            return (...args2) => {
                return call(fn, obj, ...args, ...args2)
            }
        }
        var m = 11
        function f(a, b) {
            console.log(a, b, this.m, this)
            return a + b
        }

        const obj = { m: 22 }
        console.log(bind(f, obj, 4)(1, 2))


call

  function call(Fn, obj, ...args) {
            if (obj === undefined || obj === null) {
                obj = globalThis
            }
            obj.tempFn = Fn
            let result = obj.tempFn(...args)
            delete obj.tempFn
            return result
        }

        function add(a, b) {
            return a + b + this.c
        }
        let obj = {
            c: 21
        }
        window.c = 1314
        console.log(call(add, obj, 10, 20))
        console.log(call(add, null, 10, 20))


map

   function myMap(array,callback) {
            const arr =[]
            for(let i =0;i<array.length;i++) {
                arr.push(callback(array[i],i))
            }
            return arr
        }


事件总线

    const eventBus = {}
        let callbackObj = {}
        eventBus.on = function(eventName,callback) {
            const callbacks = callbackObj[eventName]
            if(callbacks) {
                callbacks.push(callback)
            } else {
                callbackObj[eventName] = [callback]
            }
        }
        // eventBus.on('delete', (data) => {
        //     console.log('delete', data)
        // })

        // eventBus.off('add')
        // eventBus.off()

        // eventBus.emit('add', 123)
        // eventBus.emit('delete', 'abc')


 

函数节流

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        // 减少一段时间的触发频率
        // function throttle(callback,wait) {
        //     let start = 0
        //     return function(e) {
        //         let now = Date.now()
        //         if(now - start >=wait) {
        //             callback.call(this,e)
        //             start = now
        //         }
        //     }
        // }

        function throttle(callback,wait) {
            let start = 0
            return function(e) {
                let now = Date.now()
                if(now - start>= wait) {
                    callback.call(this,e)
                    start = now
                }
            }
        }
        window.addEventListener('scroll', throttle(function(e){
            console.log(e);
        }, 500));
    </script>
    <style>
        body{
            height:2000px;
            background:linear-gradient(#125, #eae);
        }
    </style>
    <script>

    </script>
</head>
<body>
    
</body>
</html>


函数防抖

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

</head>

<body>
    <input type="text">
    <script>
        // 在一定时间间隔内,将多次触发变成一次触发
   

        // 高频触发N秒只会执行一次
        // function debounce(fn, delay) {
        //     let timerId = null
        //     return function (e) {
        //         if (timerId != null) {
        //             clearTimeout(timerId)
        //         }
        //         timerId = setTimeout(() => {
        //             fn.call(this, e)
        //             timerId = null
        //         }, delay)
        //     }
        // }

        // function debounce(fn,delay) {
        //     let timerId = null
        //     return ()=>{
        //         if(timerId) {
        //             clearTimeout(timerId)
        //         }
        //         timerId = setTimeout(() => {
        //             fn()
        //         }, delay);
        //     }
        // }


        // function debounce(fn,delay) {
        //     let t = null
        //     return function() {
        //         if(t) {
        //             clearTimeout(t)
        //         }
        //         t = setTimeout(() => {
        //             fn.apply(this,arguments)
        //         }, delay);
        //     }
        // }

        function debounce(fn,delay) {
            let timerId = null
            return function() {
                if(timerId) {
                    clearTimeout(timerId)
                }
                timerId = setTimeout(() => {
                     fn.apply(this,arguments)   
                }, delay);
            }
        }   

        
        function getInputValue() {
            console.log(input.value)
        }
        let input = document.querySelector("input")
        input.addEventListener("input",debounce(getInputValue,1000))


    </script>
</body>

</html>


触发第一次

    var btn = document.getElementById("btn")
    btn.addEventListener("click",debounce(submit,1000),false)
    function debounce(fn, delay) {
        var t = null
        return function() {
            var firstClick = !t
            if (t) {clearTimeout(t)}
            if (firstClick) {
                fn.apply(this, arguments)
            }
            t = setTimeout(() => {
                t = null
            }, delay);
        }
    }

    function submit(e) {
        console.log(1)
    }


instanceof

    function Person() {

        }
        let p = new Person()
        
        function myInstanceOf(obj,Fn) {
            let prototype = Fn.prototype
            let proto = obj.__proto__
            while(proto) {
                if(proto === prototype) {
                    return true
                }
                proto = proto.__proto__
            }
            return true
        }
        
        console.log(myInstanceOf(p,Person))


newInstance

    function Person(name,age) {
          this.name = name
          this.age = age
      }  
      function newInstance(Fn,...args) {
        // 创建新对象 修改函数内部this指向并执行  返回新对象
        const obj = {}
        const result =Fn.call(obj,...args)
        // 修改新对象的原型对象
        obj.__proto__ = Fn.prototype
        return result instanceof Object ? result: obj
      }
      let obj = newInstance(Person,"张三",18)
      console.log(obj)


浅拷贝

        function shallowCopy(obj) {
            if (typeof obj !== "object") return
            let newObj = Array.isArray(obj) ? [] : {}
            for (let key in obj) {
                if (obj.hasOwnProperty(key)) {
                    newObj[key] = obj[key]
                }
            }
            return newObj
        }
        let obj = {
            a: 1,
            b: 2,
            c: {
                e: 3,
                f: 4
            },
            g: null,
            h: [8, 9, 10],
            name: 'test',
            i: { j: 1, k: 2 }
        }
        let newObj = shallowCopy(obj)
        newObj.i.j  = 8
        console.log(newObj)
        console.log(obj)


        function clone1(target) {
            if(typeof target === "object" &&target!== null) {
                if(Array.isArray(target)) {
                    return [...target]
                } else {
                    return {...target}
                }
            } else {
                return target
            }
        }
        let obj = {
            a: 1,
            b: 2,
            c: {
                e: 3,
                f: 4
            },
            g: null,
            h: [8, 9, 10],
            name: 'test',
            i: { j: 1, k: 2 }
        }
        let newObj = clone1(obj)
        newObj.i.j  = 8
        console.log(newObj)
        console.log(obj)	


 

深拷贝

简写版本

        var deepClone = function (obj) {
            if (typeof obj !== "object") {
                return obj
            }
            let newObj = Array.isArray(obj) ? [] : {}
            for (let key in obj) {
                newObj[key] = typeof obj[key] === "object" ? deepClone(obj[key]) : obj[key]
            }
            return newObj
        }


       let obj = {
            a: 1,
            b: ['e','f','g'],
            c:{f:20},
            d:{h:20},
            g: null,
            h: [8, 9, 10],
            name: 'test',
            i: { j: 1, k: 2 }
        }
        obj.b.push(obj.d)
        obj.d.h = obj.b
        function deepClone(obj,map = new WeakMap()) {
            if (typeof obj === "object" && obj !== null) {
                let cache = map.get(obj)
                if(cache) {
                    return cache
                }
                const result =Array.isArray(obj)? []:{}
                map.set(obj,result)
                for(let key in obj) {
                    if(obj.hasOwnProperty(key)) {
                        result[key] = deepClone(obj[key],map)
                    }
                }
                return result
            } else {
                return obj
            }
        }
        let newObj = deepClone(obj)
        newObj.i.j = 8
        console.log(newObj)
        console.log(obj)


 

       let obj = {
            a: 1,
            b: ['e', 'f', 'g'],
            c: { f: 20 },
            d: { h: 20 },
            g: null,
            h: [8, 9, 10],
            name: 'test',
            i: { j: 1, k: 2 }
        }
        obj.b.push(obj.d)
        obj.d.h = obj.b
        // for in 的循环性能循环很差。性能差的原因是因为: for in 会迭代对象原型链上一切 可以枚举的属性
        function deepClone(obj, map = new WeakMap()) {
            if(typeof obj ==="object" && obj !== null) {
                let cache = map.get(obj)
                if(cache) {
                    return cache
                }
                let isArray = Array.isArray(obj)
                let result = isArray ?[]:{}
                map.set(obj,result)
                if(isArray) {
                    obj.forEach((item,index) => {
                        result[index] = deepClone(item,map)
                    });
                } else {
                    Object.keys(obj).forEach(key=>{
                        result[key] = deepClone(obj[key],map)
                    })
                }
                return result
            } else {
                return obj
            }
        }
        let newObj = deepClone(obj)
        newObj.i.j = 8
        console.log(newObj)
        console.log(obj)


 

     let obj = {
            a: 1,
            b: 2,
            c: {
                e: 3,
                f: 4
            },
            g: null,
            h: [8, 9, 10],
            name: 'test',
            i: { j: 1, k: 2 }
        }
        function deepClone(obj) {
            var _obj = JSON.stringify(obj)
            var objClone = JSON.parse(_obj)
            return objClone
        }
        let newObj = deepClone(obj)
        newObj.i.j = 8
        console.log(newObj)
        console.log(obj)
       // lodash函数库实现深拷贝 let result = _.cloneDeep(test)


 

     function deepClone(obj) {
            if(typeof obj ==="object" && obj !== null) {
                const result = Array.isArray(obj)?[]:{}
                for (let key in obj) {
                    if (obj.hasOwnProperty(key)) {
                         result[key] = deepClone(obj[key])                       
                    }
                }
                return result
            } else {
                return obj
            }
        }
        let obj = {
            a: 1,
            b: 2,
            c: {
                e: 3,
                f: 4
            },
            g: null,
            h: [8, 9, 10],
            name: 'test',
            i: { j: 1, k: 2 }
        }
        let newObj = deepClone(obj)
        newObj.i.j = 8
        console.log(newObj)
        console.log(obj)


 

  const isObject = (target)=>{
            if((typeof target === "object" || typeof target === "function")&&target!=null){
                return true
            }  
            return false
        }
        function deepClone(target,map = new WeakMap()) {
            if(map.get(target)) {
                return target
            }
            let constructor = target.constructor
            if(/^(RegExp|Date)$/i.test(constructor.name)) {
                return new constructor(target)
            }
            if(isObject(target)) {
                map.set(target,true)
                let cloneTarget = Array.isArray(target)?[]:{}
                for(let prop in target) {
                    if(target.hasOwnProperty(prop)) {
                        cloneTarget[prop] = deepClone(target[prop],map)
                    }
                }
                return cloneTarget
            } else {
                return target
            }
        }
        let obj = {
            a: 1,
            b: 2,
            c: {
                e: 3,
                f: 4
            },
            g: {},
            h: [8, 9, 10],
            name: 'test',
            i: { j: 1, k: 2 }
        }
        let newObj = deepClone(obj)
        newObj.i.j = 8
        console.log(newObj)
        console.log(obj) 


        const isObject = (target) => (typeof target === "object" || typeof target === "function") && target !== null;

        function deepClone(target, map = new WeakMap()) {
            if (map.get(target)) {
                return target;
            }
            // 获取当前值的构造函数:获取它的类型
            let constructor = target.constructor;
            // 检测当前对象target是否与正则、日期格式对象匹配
            if (/^(RegExp|Date)$/i.test(constructor.name)) {
                // 创建一个新的特殊对象(正则类/日期类)的实例
                return new constructor(target);
            }
            if (isObject(target)) {
                map.set(target, true);  // 为循环引用的对象做标记
                const cloneTarget = Array.isArray(target) ? [] : {};
                for (let prop in target) {
                    if (target.hasOwnProperty(prop)) {
                        cloneTarget[prop] = deepClone(target[prop], map);
                    }
                }
                return cloneTarget;
            } else {
                return target;
            }
        }
        let obj = {
            a: 1,
            b: 2,
            c: {
                e: 3,
                f: 4
            },
            g: {},
            h: [8, 9, 10],
            name: 'test',
            i: { j: 1, k: 2 }
        }
        let newObj = deepClone(obj)
        newObj.i.j = 8
        console.log(newObj)
        console.log(obj)


        const _toString = Object.prototype.toString
        function getType(obj) {
            return _toString.call(obj).slice(8, -1)
        }
        function DFSDeepClone(obj, visited = new Set(), level = 0) {
            let res = {}
            if (getType(obj) === "Object" || getType(obj) === "Array") {
                if (visited.has(obj)) {
                    res = obj
                } else {
                    visited[level] = obj
                    visited.add(obj)
                    res = getType(obj) === "Object" ? {} : []
                    Reflect.ownKeys(obj).forEach(k => {
                        res[k] = DFSDeepClone(obj[k], visited, level + 1)
                    })
                }
            } else if(typeof obj === "function") {
                res = eval(`${obj.toString()}`)
            } else {
                res = obj
            }
            return res
        }

        let obj = {
            a: 1,
            b: 2,
            c: {
                e: 3,
                f: 4
            },
            g: {},
            h: [8, 9, 10],
            name: 'test',
            i: { j: 1, k: 2 }
        }
        let newObj = DFSDeepClone(obj)
        newObj.i.j = 8
        console.log(newObj)
        console.log(obj) 


 

寄生式组合继承

// 经典继承
function Animal() {
    this.colors = ['black', 'white']
}
Animal.prototype.say = function() {
    console.log("say")
}
function Dog() {
    Animal.call(this)
}


if(!Object.create) {
    Object.create = function(proto) {
        function F(){}
        F.prototype = proto
        return new F()
    }
    
}

Dog.prototype = Object.create(Animal.prototype)


var dog1 = new Dog()
dog1.colors.push("yellow")

var dog2 = new Dog()

console.log(dog1.colors)
console.log(dog2.colors)
dog1.say()

 


构造函数继承

       // 构造函数继承没有办法拿到原型对象上的方法
        function Animal() {
            this.colors = ["black", 'green']
        }

        Animal.prototype.getColors = function () {
            console.log(this.colors)
        }

        function Dog(name) {
            Animal.call(this)
        }

        Dog.prototype = new Animal()

        var dog1 = new Dog()
        dog1.colors.push("yellow")
        var dog2 = new Dog()

        dog1.getColors()
        dog2.getColors()



组合继承

    // https://mp.weixin.qq.com/s/_hbGus_Yo2yi18dQEZqwXg
        // 伪经典继承
        function Animal(name) {
            this.name = name
            this.colors = ["black", "white"]
        }

        Animal.prototype.say = function () {
            console.log("say")
        }

        Animal.prototype.getName = function () {
            return this.name
        }

        function Dog(name, age) {
            Animal.call(this, name)
            this.age = age
        }

        Dog.prototype = new Animal()
        Dog.prototype.constructor = Dog

        let dog1 = new Dog('奶昔', 2)
        dog1.colors.push('brown')
        let dog2 = new Dog('哈赤', 1)
        console.log(dog1)
        console.log(dog2)

        dog1.say()
        dog2.say()
        console.log(Dog.prototype === dog1.__proto__)
        console.log(Dog.__proto__ === Function.prototype)


class继承

        class Animal {
            constructor(name) {
                this.name = name
            }
            getName() {
                return this.name
            }
        }
        class Dog extends Animal {
            constructor(name,age) {
                super(name)
                this.age = age
            }
        }

        var dog1 = new Dog("大狗",1)
        var dog2 = new Dog("二狗",2)
        console.log(dog1.getName())
        console.log(dog2.getName())


圣杯模式

        var inherit = (function () {
            var Buffer = function () { }
            return function (Target, Origin) {
                Buffer.prototype = Origin.prototype
                Target.prototype = new Buffer()
                Target.prototype.constructor = Target
                Target.prototype.super_class = Origin
           }

        })()

        function Teacher() { }
        function Student() {
        }

        function Buffer() {

        }
        inherit(Student, Teacher)
        Student.prototype.age = 18
        var s = new Student()
        var t = new Teacher()

        console.log(s)
        console.log(t)



 

手写题目

死磕 36 个 JS 手写题

https://mp.weixin.qq.com/s/_hbGus_Yo2yi18dQEZqwXg

posted @ 2022-05-03 21:38  bradleydan  阅读(85)  评论(0)    收藏  举报