一些手写题

228 阅读4分钟

手写深拷贝

思路见代码注释



function depclon(sourceObj, map) {
    // 判断是否为对象或者数组
    // object()判断不严谨,如 var a = Number(1), Object(a) === a 无法判断
    // 此处 需要改为 typeof sourceObj === 'object' && object !== null判断
    if(Object(sourceObj) !== obj) {
        return sourceObj
    }
    // 考虑循环引用,如a.ref = a
    if(!map) {
        map = new WeakMap()
    }
    // 判断是否是数组还是对象,
    const target = Array.isArray(sourceObj) ? [] : {}
    if(map.has(sourceObj)) return sourceObj.get(sourceObj)
    map.set(sourceObj, target)
    // for in可以通用 对 object和array遍历
    for (const key in sourceObj) {
        if (Object.hasOwnProperty.call(sourceObj, key)) {
            const element = sourceObj[key];
            if(Object(element) === element) {
                target[key] = depclon(element, map)
            } else {
                target[key] =  map
            }
        }
    }
    return target

}

可参考 blog.csdn.net/qq_41846861…

合并两个有序数组

思路: 其实就是以一个数组为基准,不断遍历另外一个数组,以下面的例子来说就是 用b里面的第n项和a中的每一项作对比,找到合适的位置后插入,然后继续拿出b中的下一项继续



var a = [1,3,5]
var b = [2,4,6,8]

function merge(a, m, b, n) {
    let i = 0
    let j = 0
    while(j < n) {
        if(b[j] > a[i]) {
            i++
        } else {
            a.splice(i++, 0,b[j++])
        }
    }
}
merge(a, 3, b, 4)

promise并发请求控制

思路: 用promise.all实现,比如要求同时并发3个请求,总共10个请求,那么用一个长度为3的空数组遍历,并用promise.all包裹,此时会并发三个请求,在每一个请求完成的时候将10个请求中剩余的(此时还有7个)请求循环调用,知道剩余请求为空

juejin.cn/post/691801…

深度遍历 广度遍历

juejin.cn/post/695617… juejin.cn/post/692760…

面试真题 手写1

完成format函数,来对输入的对象转换成字符串并格式化打印。(不能用json.stringfry)

例1

obj = [1,2,[3,4]]

console.log(format(obj))

输出

[
    1,
    2,
    [
        3,
        4
    ]
]

例2

obj = {name:'xiaoming',age:12,phone:[110,120,{other:130}],skill:{changtiao:80,rap:90,lanqiu:100}}

console.log(format(obj))

{
    "name":'xiaoming',
    "age": 12,
    "phone":[
        110,
        120,
        {
            "other":130
        }
    ],
    "skill":{
       "changtiao":80,
       "rap":90,
       "lanqiu":100
    }
}

实现 本题也可叫做 # 模拟实现JSON.stringiry 的格式化输出

另外也可以 利用nodeJS中的util模块中的 util.inspect(obj[,options])

nodejs.org/api/util.ht…

其他题目

手写lrucache (真题

两种思路, 在js中可利用特有的 map结构即可 segmentfault.com/a/119000003… 利用 双向链表(保证有序) + object(保证取值方便) juejin.cn/post/694842…

手写 userequest (真题

mobx redux 区别 (真题

最长递增子序列

juejin.cn/post/702970…

typescript

  • const func = (a, b) => a + b; 要求编写Typescript,要求a,b参数类型一致,都为number或者都为string

想了半天只想到用重载解决 ,泛型的话实现不了

function add(a:string, b:string): string;

//带有数字类型参数的函数 function add(a:number, b:number): number;

//函数定义 function add(a: any, b:any): any {
return a + b;
}
const dd = add(1,1)

const dd2 = add('1','3')

或者 interface的重载 image.png

手写 useprevious

为什么如下可以实现,因为 useEffect是在return之后执行,所以每次会返回上一次的值


function useprevies(value) {
    const prevalueRef = useRef()
    useEffect(()=>{
        prevalueRef.current = state
    })
    rerurn prevalueRef.current
}

手写快速排序

分治 +递归


var testarr = [1,5,2,7,1,88,6,15]
function qrsort(arr = []) {
    if(arr.length <= 1) return arr
    const pivot =arr.shift()
    const left = []
    const right = []
    arr.forEach(item => {
        item < pivot ? left.push(item) : right.push(item)
    })
    return qrsort(left).concat([pivot], qrsort(right))
}

testarr(testarr)

大数相加


function plus(str1, str2) {
    while(str1.length < str2.length) {
        str1 = '0' + str1
    }
    while(str2.length < str1.length) {
        str2 = '0' + str2
    }
    let res = ''  // 结果
    let pat = 0 // 进位
    let i  = str1.length -1 
    while(i >= 0) {
       var ret = Number(str1[i]) + Number(str2[i]) + pat
       res = ret % 10 + res
       pat = ret> 10  ? 1 : 0
       i --
    }
    return pat === 1 ? '1'+ res  : res
}

判断左右括号


function isValid3(str) {
    const arr = []
    const lefttoright = {
        '(': ')',
        '{': '}',
        "[": ']',
    }
    
     for(let i =0 ;i<str.length ;i++) {
         let item = str[i]
         
         if(lefttoright[item]) {
             // zuo kuo hao 
             arr.push(item)
         } else {
          
           if(!arr.length) {
               return false
           }
           const top = arr.pop()
           if(lefttoright[top] !== item) {
               return false
           }
         }
     }
     return  !arr.length
   
   }
   
   isValid3('()')

jsbridge原理

注意 原生和webview中可以传递字符串 没办法传递函数 native在webview中声明一个对象 并包含方法 invoke:(name,param, success,errcess)=>{} 所以客户端通过维护一个 函数key映射 {callback_$1: callback1} 将key传递给native

www.cnblogs.com/mengff/p/12…

blog.csdn.net/weixin_3984…

选择排序

复杂度 o(n2), 双层for循环+交换两个变量


 function selectsort(arr) {
    let temp
    let minidx
    for(let i = 0; i<arr.length; i++) {
        minidx = i
        for(let j = i+1;j<arr.length; j++) {
            if(arr[j] < arr[minidx]) {
                minidx = j
            }
        }
        let temp = arr[i]
        arr[i]= arr[minidx]
        arr[minidx] = temp
    }
    return arr
   }

冒泡排序

双层循环
两两比较 每次循环能比较出一个最大值。 内层循环每次的终点-1


 function bublesort(arr) {
    for(let i = 0; i<arr.length; i++) {
        for(let j = 0;j<arr.length-1-i; j++) {
            if(arr[j] < arr[j+1]) {
                let temp = arr[j]
                arr[j] = arr[j+1]
                arr[j+1] = temp
            }
        }
    }
    return arr
   }

插入排序

和冒泡的区别, 冒泡复杂度o(n2), 插入比冒泡相对好一些,操作步骤较少


   
function  insersort(arr) {
    for(let i = 1; i<arr.length; i++) {

        let preidx = i-1
        let current = arr[i]
        while(preidx >=0 && arr[preidx] > arr[i]) {
            arr[preidx+1] = arr[preidx]
            preidx--
        }

        arr[preidx+1] = current
    }
    return arr
}

希尔排序


function shellSort(array) {
  if (array.length <= 1) return array; // 如果数组长度为1,直接返回
  var gap = Math.floor(array.length / 2);
  while (gap > 0) {
    for (var i = gap; i < array.length; i++) {
      var j = i;
      var temp = array[j];
      while (j > 0 && array[j - gap] > temp) { // 若array[j - gap]>temp(即array[j]) 则互换位置
        array[j] = array[j - gap]; // 这里可看成是将 j-gap 后移一个 gap 位 //TODO 插入排序这里是后移一位
        array[j - gap] = temp; // 由于不像插入排序那样需要比较很多个元素,而是两个数的比较,此处将大得值往前移一个 gap 位即可
        j -= gap; // 跳出循环的条件
      }
    }
    gap = Math.floor(gap / 2); // 减小增量
  }
  return array;
}
var arr = [9, 1, 2, 5, 7, 4, 8, 6, 3, 5];
console.log(shellSort(arr))

并归排序


function mergeSort(array) {
  if (array.length <= 1) return array; // 如果数组长度为1,直接返回。等到merge中排序合并
  var m = Math.floor(array.length / 2);
  var left = mergeSort(array.slice(0, m)); // 不断递归调用最终排列好 left 数组
  var right = mergeSort(array.slice(m, array.length)); // 不断递归调用最终排列好 right 数组
  return merge(left, right);
}
// 排列并合并左右数组
function merge(left, right) {
  var resArr = [] // 新的空数组
  while (0 < left.length && 0 < right.length) { // 每次比较取出一个相对小的元素放入resArr中
    resArr.push(left[0] <= right[0] ? left.shift() : right.shift()) // array.shift() 取第一个数,并移除该数组中的第一个数
  }
  return resArr.concat(left, right);
}

var arr = [8, 7, 6, 5, 4, 3, 2, 1];
console.log(mergeSort(arr)); // [1, 2, 3, 4, 5, 6, 7, 8]

计数排序


function countingSort(arr, maxValue) {
    var bucket = new Array(maxValue + 1),
        sortedIndex = 0;
        arrLen = arr.length,
        bucketLen = maxValue + 1;
 
    for (var i = 0; i < arrLen; i++) {
        if (!bucket[arr[i]]) {
            bucket[arr[i]] = 0;
        }
        bucket[arr[i]]++;
    }
 
    for (var j = 0; j < bucketLen; j++) {
        while(bucket[j] > 0) {
            arr[sortedIndex++] = j;
            bucket[j]--;
        }
    }
 
    return arr;
}

桶排序

有弊端,了解思想即可, 分为多个桶,每个桶里分别排序,然后在合并, 缺陷为 每个桶的大小不好确定,比如0.11, 0.12, 0.13 , 0.14, 0.91, 1.00

有题目得知,数值范围在0-1之间, 我们可以平均分为四个桶, 0-0.25, 0.25-0.5, 0.5-0.75, 0.75-1.00,
但是缺陷为 数据明显都会分布在0.11-0.15之间, 所以导致四个桶 数据不均

基数排序

适用于正整数 先个位数排序,在十位数排序,在百位排序, 以此类推 juejin.cn/post/703890…

计算 ’2+4/4-1‘

letcode 224 和227 ,用栈去解决, 遍历字符串, 如果是数字的话复制给全局 累计 判断四则符号, 加号的话 数字push进数组 -好的话 数字加负号push进数组 乘除的话 先运算在 push进数组 用reduce求和 leetcode-cn.com/problems/ba…

块级作用域(真题 blm)、

this(真题 blm)

继承 webpack 怎么转成es5(真题 blm)

vue的compute中 没使用, 会有watcher吗(真题 blm)

垃圾回收(真题 blm)

vue diff.

vue router 哪些组件

vue响应式原理

type interface区别

event loop

游览器渲染原来