前端面试必刷手写题系列 [1]

1,342 阅读5分钟

这个系列也没啥花头,就是来整平时面试的一些手写函数,考这些简单实现的好处是能看出基本编码水平,且占用时间不长,更全面地看出你的代码实力如何。一般不会出有很多边界条件的问题,那样面试时间不够用,考察不全面。

平时被考到的 api 如果不知道或不清楚,直接问面试官就行, api 怎么用这些 Google 下谁都能马上了解的知识也看不出水平。关键是在实现过程,和你的编码状态习惯思路清晰程度等。

注意是简单实现,不是完整实现,重要的是概念清晰实现思路清晰,建议先写伪代码,再实现具体功能。

1. Object.keys()

是什么

MDN传送门

Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。

直接看例子吧

// simple array
var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']

// array like object
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']

// array like object with random key ordering
var anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj)); // console: ['2', '7', '100']

// getFoo is a property which isn't enumerable
var myObj = Object.create({}, {
  getFoo: {
    value: function () { return this.foo; }
  }
});
myObj.foo = 1;
console.log(Object.keys(myObj)); // console: ['foo']

如果你想获取一个对象的所有属性,,甚至包括不可枚举的,请查看 Object.getOwnPropertyNames

简单手写实现

思路

  1. 一般实现的都是一个函数,有函数就有返回值,这题是数组,先定义结果 res = []
  2. 了解这个函数的实现过程,这题太简单,就是遍历对象推入自身可枚举属性的属性名就行。
  3. 多思考一步,面试官可能会想让你拓展的地方,就是 for in 遍历会连原型链上的可枚举属性一起遍历,如何处理。

实现

因为是第一题,我就写清楚思考过程,后面的就不写太细了

  1. 这里有个第 0 步,写个测试用例先,在你写的过程中也好调试,也可以吹一波 TDD
let obj = {'a': 1, '2': '22', '66': 'c'}
Object.prototype.xxxprop = { 'xxx': 'xxx' }

console.log(Object.keys(obj)) // [ '2', '66', 'a' ]
  1. 那我们就先写出伪代码,理清思路
const getObjectKeys = (obj) => {
  // 先定义返回值 res
  const res = []
  // 处理逻辑,遍历所有可枚举属性,推入 res
  ...
  return res
}
  1. 实现主逻辑
const getObjectKeys = (obj) => {
  // 先定义返回值 res
  const res = []
  // 处理逻辑,遍历所有可枚举属性,推入 res
  for (prop in obj) {
    res.push(prop)
  }
  return res
}
console.log(getObjectKeys(obj)) // [ '2', '66', 'a', 'xxxprop' ]
// 果然把原型链上的可枚举属性一起遍历输出了
  1. 写完整这些特殊的点,当然 2,3你可以一步到位,我分步骤是为了举例,其他复杂题最好清楚分出步骤。
const getObjectKeys = (obj) => {
  // 先定义返回值 res
  const res = []
  // 处理逻辑,遍历所有可枚举属性,推入 res
  for (prop in obj) {
    // 为了过滤掉原型上的属性用 hasOwnProperty
    if (obj.hasOwnProperty(prop)) {
      res.push(prop)
    }
  }
  return res
}

console.log(getObjectKeys(obj)) // [ '2', '66', 'a' ]

2. Object.values()

是什么

MDN传送门

Object.values()方法返回一个给定对象自身的所有可枚举属性的数组,值的顺序与使用for...in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。

Object.keys()区别就在于 返回的不是

var obj = { foo: 'bar', baz: 42 };
console.log(Object.values(obj)); // ['bar', 42]

// array like object
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.values(obj)); // ['a', 'b', 'c']

// array like object with random key ordering
// when we use numeric keys, 
// the value returned in a numerical order according to the keys
var an_obj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.values(an_obj)); // ['b', 'c', 'a']

// getFoo is property which isn't enumerable
var my_obj = Object.create({}, { 
    getFoo: { value: function() { return this.foo; } } 
});
my_obj.foo = 'bar';
console.log(Object.values(my_obj)); // ['bar']

// non-object argument will be coerced to an object
console.log(Object.values('foo')); // ['f', 'o', 'o']

简单手写实现

实际我们还是根据这几个步骤来写,这里我们就省略步骤了,注意步骤非常重要

  1. 写个测试用例
  2. 写出伪代码,思路注释
  3. 实现主逻辑
  4. 边界特殊情况适当考虑

这里就直接写了因为根上面几乎一样

let obj = {'1': 1, '2': 3, '3': 'c'}
Object.prototype.xxxprop = { 'xxx': 'xxx' }

const getObjectValues = (obj) => {
  const res = []
  for (prop in obj) {
    if (obj.hasOwnProperty(prop)) {
      // 这里返回值就行
      res.push(obj[prop])
    }
  }
  return res
}

console.log(getObjectValues(obj)) // [ 1, 3, 'c']

3. Object.entries()

是什么

MDN传送门

Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。

const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]

// array like object
const obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.entries(obj)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]

// array like object with random key ordering
const anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.entries(anObj)); // [ ['2', 'b'], ['7', 'c'], ['100', 'a'] ]

// getFoo is property which isn't enumerable
const myObj = Object.create({}, { getFoo: { value() { return this.foo; } } });
myObj.foo = 'bar';
console.log(Object.entries(myObj)); // [ ['foo', 'bar'] ]

// non-object argument will be coerced to an object
console.log(Object.entries('foo')); // [ ['0', 'f'], ['1', 'o'], ['2', 'o'] ]

技巧

new Map() 构造函数接受一个可迭代的entries。借助Object.entries方法你可以很容易的将Object转换为Map:

var obj = { foo: "bar", baz: 42 };
var map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baz: 42 }

简单手写实现

let obj = {'1': 1, '3': 'c'}
Object.prototype.xxxprop = { 'xxx': 'xxx' }

const getObjectEntries = (obj) => {
  const res = []
  for (prop in obj) {
    if (obj.hasOwnProperty(prop)) {
      // 这里返回键值对数组就行
      res.push([prop, obj[prop]])
    }
  }
  return res
}

console.log(getObjectEntries(obj)) // [ [ '1', 1 ], [ '3', 'c' ] ]
console.log(Object.entries(obj)) // [ [ '1', 1 ], [ '3', 'c' ] ]

另外向大家着重推荐下这位大哥的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列

今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 搜索我的微信号infinity_9368,可以聊天说地 加我暗号 "天王盖地虎" 下一句的英文,验证消息请发给我 presious tower shock the rever monster,我看到就通过,暗号对不上不加哈,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧

参考