前端面试手写代码题实践

673 阅读2分钟

题目一 【完善sum函数】

题目介绍

如下为一段代码,请完善 sum 函数,使得sum(1,2,3,4,5,6) 函数返回值为 21 ,需要在 sum 函数中调用 asyncAdd 函数进行数值运算,且不能修改 asyncAdd 函数

/**
 * 请在 sum函数中调用此函数,完成数值计算
 * @param {*} a 要相加的第一个值
 * @param {*} b 要相加的第二个值
 * @param {*} callback 相加之后的回调函数
 */
function asyncAdd(a,b,callback) {
  setTimeout(function(){
   callback(null, a+b)
  },1000)
}

/**
 * 请在此方法中调用asyncAdd方法,完成数值计算
 * @param  {...any} rest 传入的参数
 */
async function sum(...rest) {
  // 请在此处完善代码
}

let start = window.performance.now()
sum(1, 2, 3, 4, 5, 6).then(res => {
  // 请保证在调用sum方法之后,返回结果21
  console.log(res)
  console.log(`程序执行共耗时: ${window.performance.now() - start}`)
})

答案

> 3s

/**
 * 请在此方法中调用asyncAdd方法,完成数值计算
 * @param  {...any} rest 传入的参数
 */
// 二分法
async function sum(...arr) {
  let res = []
   for (let i = 0;i<arr.length/2; i++) {
     if(i === arr.length -i-1) {
      res.push(arr[i])
     } else {
      res.push(
        new Promise((resolve) => {
            asyncAdd(arr[i], arr[arr.length - i -1], (a,b) => {
              resolve(b)
            })
          })
        )
     }
   }
  res = await Promise.all(res)
   if(res.length>=2) {
    return await sum(...res)
   } else {
     return res;
   }
}

console.time('time')
sum(1, 2, 3, 4, 5, 6).then(res => {
  console.log(res[0])
  // 请保证在调用sum方法之后,返回结果21
  console.timeEnd('time')
})

>1s

async function sum(...rest) {
  let result = 0
  // 隐氏类型转换, 对象 + 数字,会先调用对象的toString 方法
  const obj = {}
  obj.toString = function() {
    return result
  }
  const promises = []
  for(let num of rest) {
    promises.push(new Promise((resolve) => {
      asyncAdd(obj, num, (_, res) => {
        resolve(res)
      })
    }).then(res => {
      // 在这里将 result的值改变之后,obj.toString 的返回值就变了,这时候下一个setTimeout调用时就使用了新值
      result = res
    }))
  }
  await Promise.all(promises)
  return result
}

// 执行成功,执行时长大于1秒小于2秒
sum(1, 2, 3, 4, 5,6).then(res => {
   // 请保证在调用sum方法之后,返回结果21
  console.log(res)
  console.timeEnd('time')
})

题目二 【模拟实现new操作符】

题目介绍

请模拟实现new操作符,使下面代码正常运行

function myNew(constructor, ...rest) {
 // 请在此处完善代码,不能直接使用 new 操作符
}
function Fun(name,sex) {
  this.name = name
  this.sex = sex
}
Fun.prototype.getUserInfo = function() {
  return `我的姓名 ${this.name},我的性别 ${this.sex}`
}

const fun = myNew(Fun,'子君','男')
// 我的姓名子君,我的性别男
console.log(fun.getUserInfo())

答案

  1. 创建一个新的对象;
  2. 将构造函数的作用域赋给新的对象;
  3. 执行构造函数中的代码;
  4. 返回新的对象;
function myNew(constructor, ...rest) {
  if(typeof constructor !== 'function') {
    return constructor;
  }
  const _constructor = Object.create(constructor.prototype);
  const obj = constructor.apply(_constructor, rest);
  if(typeof obj === 'object') {
    return obj;
  } else {
    return _constructor;
  }
}

题目三 【symbol和对象输出考察】

题目介绍

请说出以下代码输出内容

const a = {}
const b = Symbol('1')
const c = Symbol('1')
a[b] = '子君'
a[c] = '君子'

// 我是子君还是君子呢
console.log(a[b])

const d = {}
const e = {key: '1'}
const f = {key: '2'}
d[e] = '子君'
d[f] = '君子'

// 我是子君还是君子呢
console.log(d[e])

答案

const a = {}
const b = Symbol('1')
const c = Symbol('1')
a[b] = '子君'
a[c] = '君子'

// 输出子君
console.log(a[b])

const d = {}
const e = {key: '1'}
const f = {key: '2'}
d[e] = '子君'
d[f] = '君子'

// 输出君子
console.log(d[e])

对于第一个输出,Symbol()函数会返回「symbol」类型的值,而 Symbol 函数传的参数仅仅是用于标识的,不会影响值的唯一性 对于第二个输出, 因为 e 和 f 都是对象,而对象的 key 只能是数值或字符,所以会将对象转换为字符,对象的 toString 方法返回的是[object Object], 所有输出的是君子

题目四 【手写Object.create】

题目介绍

手写Object.create

funtion myCreate(obj) {
  function F() {};
  F.prototype = obj;
  return new F();
}

题目五 【手写instanceOf】

题目介绍

手写instanceOf

function myInstanceof(left, right) {
  right = right.prototype;
  left = left.__proto__;
  while(true) {
    if(left === null) {
      return false;
    }
    if(right === left) {
      return true;
    }
    left = left.__proto__;
  }
}

题目五【二分查找】

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
const search = function(nums, target) {
  let left = 0,
      right = nums.length - 1,
      mid;
  while(left <= right) {
      mid = Math.floor((left + right) / 2);
      if(nums[mid] < target) {
        left = mid + 1;
      } else if(nums[mid] > target) {
        right = mid - 1;
      } else {
        return mid;
      }
  }
  return -1;
}

题目六【手写Promise.all】

const one = new Promise((resolve) => {
  setTimeout(() => {
    console.log('one')
    resolve()
  }, 1000);
});
const two = new Promise((resolve) => {
  setTimeout(() => {
    console.log('two')
    resolve()
  }, 2000);
});
const three = new Promise((resolve) => {
  setTimeout(() => {
    console.log('three')
    resolve()
  }, 3000);
});

Promise.all([one, two, three]).then(() => {
  console.log('Promise.all success')
})

// 实现all方法
const all = function (promises) {
  let resolveSum = 0;
  return new Promise((resolve, reject) => {
    promises.forEach(promise => {
      promise.then(() => {
        resolveSum++;
        if (resolveSum === promises.length) {
          resolve()
        }
      }).catch(() => {
        reject()
      })
    })
  })
}

all([one, two, three]).then(() => {
  console.log('all success')
})

// one
// two
// three
// Promise.all success
// all success