小言_互联网的博客

反复刷这些javascript面试手写题,我感觉我真的变强了(一)

281人阅读  评论(0)

用正则能实现的手写题

前段时间刚好复习了正则,所以把正则的写前面

实现千分位分隔符

题目描述:实现将一个数从各位数开始,每距离一个千分位添加一个分割符 ‘ ,’
如输入: 12345678.32423432
输出:12,345,678.32423432

这道题在最近一两个月的面试中遇到两次,可以分别有字符串和数组的一些方法结合解决,也可以用正则解决,我觉得正则可能更难以理解

第一种方法:


const num = 12345678.32423432

function getForm(num) {
   
  let arr = num.toString().split('.')
  // 取出整数部分
  let arr0 = arr[0].split('')
  // console.log(arr0);
  let stack = []
  let i = 0
  while (arr0.length > 0) {
   
    // 没3位添加一个分割符
    if (i % 3 == 0 && i !== 0) {
   
      stack.push(',')
    }
    stack.push(arr0.pop())
    i++
  }
  let res = stack.reverse()
  console.log(res);
  // 考虑是否存在小数部分
  if (arr[1]) {
   
    return res.join('') + '.' + arr[1]
  } else {
   
    return res.join('')
  }
}

console.log(getForm(num));

第二种方法用正则解决:

function regForm(num) {
   
  // console.log(num.toString());
  return num.toString().replace(/\d+/, (p) => {
   
    return p.replace(/\d(?=(\d{3})+$)+/g, (p1, p2) => {
   
      return p1 + ','
    })
  })
}

实现一个trim()

实现string原型上的trim()方法:
解决方法有很多,我常用的是下面这两个

String.prototype.my_trim = function () {
   
  return this.replace(/^\s+/, '').replace(/\s+$/, ' ')
}

String.prototype.trim = function() {
   
  return  this.replace(/^\s+|\s+$/g, '');
}

取出连续重复的字符

取出 :'sadddddddddddddsssssssssssssdddddddasddd’重复的字符
最终为 [“ddddddddddddd”, “sssssssssssss”, “ddddddd”, “ddd”]

面试腾讯暑期实习生遇到此题,我当时真的菜没做出来,回过头来发现真简单


let a = 'sadddddddddddddsssssssssssssdddddddasddd'

console.log(a.match(/([a-z])\1+/ig));

解析url参数为对象形式

const url = 'http://www.baidu.com/we/index.html?id=098&aaa=123&ccc=456'


function parseParam(url) {
   
  let arr = url.split('?')[1].split('&')
  console.log(arr);
  let obj = {
   }
  arr.forEach(item => {
   
    console.log(item.split('='));
    let [key, value] = item.split('=')
    if (/^\d+$/.test(value)) {
   
      value = parseInt(value)
    }
    obj[key] = value
  })
  return obj

}

console.log(parseParam(url));

关于闭包的手写题

自我感觉这部分的手写题能够全部理解的话,对于闭包的理解会更加深刻

利用高阶函数实现函数缓存

高阶函数应该就是输入参数是函数,返回也是一个函数

var add = function (a) {
   
  return a + 1
}


function memo(fn) {
   
  const cache = {
   }
  return function (...ret) {
   
    let key = JSON.stringify(ret)
    return cache[key] || (cache[key] = fn.apply(fn, [...ret]))
  }
}

const adder = memo(add)
console.log(adder);
console.log(adder(1));
console.log(adder(1));
console.log(adder(3));
console.log(adder(3));

手写call,apply,bind

这几个函数只有把手写学会才会理解的更深刻

点击查看详细解说分别手写call,apply,bind

柯里化-实现实现一个add(1)(2)(3)

具体要求就是能使本来函数add(1,2,3)变成add(1)(2)(3)

具体思路就是将参数用递归的方式一个一个的传入目标函数

function curry(fn, args) {
   
  var ofArgs = args || []
  var len = fn.length
  var self = this
  // 
  return function (...ret) {
   
    // ret是后面传入的函数
    var currentArg = [...ofArgs, ...ret]
    console.log(currentArg);
    // 如果当前参数数组的长度小于fn的要求长度  那么继续递归
    if (len > currentArg.length) {
   
      return curry.call(self, fn, currentArg)
    }
    return fn.apply(self, currentArg)
  }
}

const add = function (a, b, c) {
   
  return a + b + c
}

const newFn = curry(add)

// newFn(1)(2)(3)
console.log(newFn(1)(2)(3));

防抖和节流

防抖和节流

关于对象

手写深拷贝

拷贝一个地址不同其他完全相同的对象

function deepClone(obj) {
   

  if (typeof obj !== 'object') {
   
    return obj
  }
  let res

  // 数组和对象的限定
  if (Array.isArray(obj)) {
   
    res = []
  } else {
   
    res = {
   }
  }

  //一层层递归赋值
  for (let key in obj) {
   
    console.log(key);
    if (obj.hasOwnProperty(key)) {
   
      res[key] = obj[key]
    }
  }
  return res
}

let book = {
   
  name: "局外人",
  types: {
   
    t1: "中文版",
    t2: "英文版",
    a: {
   
      c: 2
    }
  }
}
5


let book_clone = deepClone(book)
console.log(book_clone === book);
console.log(book_clone);

手写深度比较

深度比较两个对象的值是否完全相同

function isEqual(obj1, obj2) {
   
  // 判断两个是不是对象
  if (typeof obj1 !== 'object' && typeof obj2 !== 'object'
    && obj1 !== null && obj2 !== null) {
   
    return obj1 === obj2
  }

  if (obj1 === obj2) {
   
    return true
  }
  // 先取出obj1和obj2的keys,比较个数
  let leng1 = Object.keys(obj1).length
  let leng2 = Object.keys(obj2).length
  // console.log(leng1);
  if (leng1 !== leng2) {
   
    return false
  }
  // 以obj1为基准和obj2递归比较
  for (let key in obj1) {
   
    const res = isEqual(obj1[key], obj2[key])
    if (!res) {
   
      return false
    }
  }

  return true
}

const obj1 = {
   
  a: 2,
  b: 'a',
  c: {
   
    e: 'f',
    f: 's'
  }
}

const obj2 = {
   
  a: 2,
  b: 'a',
  c: {
   
    e: 'f',
    f: 's',
    // a: 41
  }

}

console.log(isEqual(obj1, obj2));



关于数组

数组去重

最简单的去重:用set


var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, 'NaN', 0, 0, 'a', 'a', {
   }, {
   }];
console.log(unique(arr));
// 注意Set是能够去掉NaN的重复的

// [...new Set(arr)]

function unique(arr) {
   
  return Array.from(new Set(arr))
}


使用indexOf无法去除 NaN的重复 indexOf(NaN)永远等于-1


var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, 'NaN', 0, 0, 'a', 'a', {
   }, {
   }];
console.log(unique(arr));


function unique(arr) {
   
  if (!Array.isArray(arr)) {
   
    {
   
      console.log('is nor a array');
    }
  }
  const res = []
  arr.forEach(element => {
   
    if (res.indexOf(element) === -1) {
   
      res.push(element)
    }
  });
  return res
}

includes也是能够去掉NaN的重复的


var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, 'NaN', 0, 0, 'a', 'a', {
   }, {
   }];
console.log(unique(arr));

function unique(arr) {
   
  if (!Array.isArray(arr)) {
   
    throw new TypeError('is not array')
  }
  const new_arr = []
  arr.forEach(e => {
   
    if (!new_arr.includes(e)) {
   
      new_arr.push(e)
    }
  })

  return new_arr
}

splice使用此函数特别需要注意的一点:会改变数组,改变数组的长度

var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, 'NaN', 0, 0, 'a', 'a', {
   }, {
   }];
console.log(unique(arr));


function unique(arr) {
   
  let len = arr.length
  for (let i = 0; i < len; i++) {
   
    for (let j = i + 1; j < len; j++) {
   
      if (arr[i] == arr[j]) {
   
        //       console.log(arr);
        arr.splice(j, 1)
        // console.log(arr);
        j--;
      }
    }
  }
  return arr
}

用filter+hasOwnProperty两个空对象也能去重

var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, 'NaN', 0, 0, 'a', 'a', {
   }, {
   }];
console.log(unique(arr));

function unique(arr) {
   
  var obj = {
   };
  return arr.filter(function (item, index, arr) {
   
    console.log(item);
    console.log(typeof item + item);
    // console.log(obj[typeof item + item]);
    // 判断obj对象是否有这个属性,如果有(说明数组元素重复)直接返回false过滤掉数组中的重复元素
    // 如果没有,为obj对象添加上这个属性
    return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
  })
}

数组乱序

主要用到的api是Match.random和set

function disorder(arr) {
   
  let len = arr.length
  let res = []
  let remember = new Set()
  // console.log(remember.size);
  while (remember.size < len) {
   

    let randomNum = Math.floor(len * Math.random())
    if (!remember.has(randomNum)) {
   
      res.push(arr[randomNum])
      remember.add(randomNum)
    }
  }
  return res


}

console.log(disorder([1, 2, 3, 4, 5, 6, 7, 8, 9]));

手写数组filter方法

先具体了解一下filter -MDN

下面的call后面的参数和上面的参数是对应的

Array.prototype.my_filter = function (fn, context) {
   
  if (Object.prototype.toString.call(this) !== '[object Array]') {
   
    throw new TypeError('is not a array')
  }

  let newArr = []
  for (let i = 0; i < this.length; i++) {
   
    let t = fn.call(context, this[i], i, this)
    if (t) {
   
      newArr.push(this[i])
    }
  }
  return newArr

}



const arr = [1, 2].my_filter(x => x == 2)

console.log(arr);



实现数组的flat方法

要实现拍平一个数组,可以用concat或剩余运算符

第一种实现用reduce+递归

const arr = [1, 2, 3, 4, [1, 2, 3, [1, 2, 3, [1, 2, 3]]], 5, "string", {
    name: "弹铁蛋同学" }];
function flat(arr) {
   
  return arr.reduce((pres, cur) => {
   
    return pres.concat(Array.isArray(cur) ? flat(cur) : cur)
  }, [])
}

第二种实现方式用栈

const arr = [1, 2, 3, 4, [1, 2, 3, [1, 2, 3, [1, 2, 3]]], 5, "string", {
    name: "弹铁蛋同学" }];

console.log(flat(arr, 2));

function flat(arr) {
   
  let stack = [].concat(arr)
  let res = []

  while (stack.length !== 0) {
   
    const i = stack.pop()
    if (Array.isArray(i)) {
   
      stack.push(...i)
    } else {
   
      res.unshift(i)
    }
  }
  return res
}

其他

实现一个new

一个new的实现需要经过这几步

  1. 创建一个新的对象
  2. 将构造函数的作用域指向这个对象,改变this的指向
  3. 执行构造函数中的代码
  4. 返回新的对象
function New() {
   
  // 创建一个新对象
  const obj = {
   }
  // 获取第一个参数即为构造函数
  const constr = [...arguments].shift()
  console.log(constr);
  console.log(arguments);
  // 将obj的原型指向构造函数的原型对象,这样obj就可以访问构造函数原型上的属性
  obj.__proto__ = constr.prototype
  // 执行构造函数
  constr.apply(obj, [...arguments].slice(1))
  return obj
}

function Parent(age, name) {
   
  this.age = age
  this.name = name
  this.sayAge = function () {
   
    console.log('this.age :', this.age)
  }
}
Parent.prototype.sayName = function () {
   
  console.log('this.name :', this.name)
}

let son = new Parent(18, 'lining')
let newSon = New(Parent, 18, 'lining')

console.log('son :', son)       // son : Parent { age: 18, name: 'lining', sayAge: [Function] }
console.log('newSon :', newSon)

实现一个instanseof

instanceof主要实现原理就是只要右边变量的prototype在左边变量的原型链上即可
因此instanceof 在查找的过程中会 遍历左边变量的原型链,知道找到右边变量的prototype

 function My_instanceof(left,right){
   
   let rightProto = right.prototype;
   left = left.__proto__

   while(true){
   
     if(left == null){
   
       return false
     }
     if(left === rightProto){
   
       return true
     }
     left = left.__proto__
   }

 }

console.log( My_instanceof(1,Number));


转载:https://blog.csdn.net/weixin_43342105/article/details/116207963
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场