阿里笔试题:链式调用、对象比较以及对象是否存在循环引用
最近小伙伴参加了阿里的面试,其中有一轮就是笔试环节,面试官就给小伙伴出了三道笔试题,废话不多说我们来看看是哪三道题目吧。
题目一
// 实现一个find函数,并且find函数能够满足下列条件
// title数据类型为string|null
// userId为主键,数据类型为number
// 原始数据
const data = [
{userId: 8, title: 'title1'},
{userId: 11, title: 'other'},
{userId: 15, title: null},
{userId: 19, title: 'title2'}
];
// 查找data中,符合条件的数据,并进行排序
const result = find(data).where({
"title": /\d$/
}).orderBy('userId', 'desc');
// 输出
[{ userId: 19, title: 'title2'}, { userId: 8, title: 'title1' }];
在JS代码中,链式调用是非常常见的,如jQuery、Promise等中都使用了链式调用,链式调用是得我们的代码更加的清晰。我们知道JS的链式调用有很多种方式。
1、jQuery链式调用是通过return this的形式来实现的,通过对象上的方法最后加上return this,把对象再返回回来,对象就可以继续调用方法,实现链式操作了。
const Student = function() {};
Student.prototype.setMathScore = function(age){
this.math = math;
return this;
}
Person.prototype.setEnglishScore = function(weight){
this.english = english;
return this;
}
Person.prototype.getMathAndEnglish = function(){
return `{math: ${this.math}, english: ${this.english}}`;
}
const student = new Student();
const score = student.setMathScore(130).setEnglishScore(118).getMathAndEnglish();
console.log(score); // {math: 130, english: 118}
2、我们还可以直接返回对象本身来实现链式调用。
const student = {
math: 0,
english: 0,
setMathScore: function(math){
this.math = math;
return this;
},
setEnglishScore: function(english){
this.english = english;
return this;
},
getMathAndEnglish: function(){
return `{math: ${this.math}, english: ${this.english}}`;
}
};
const score = student.setMathScore(10).setEnglishScore(30).getMathAndEnglish();
console.log(score); // {math: 130, english: 118}
当然还有其他实现链式调用的方式,本文就不展开来说了,那么我们来说一说本题吧,很明显本题是一个链式调用,但是和我们上面的介绍又有区别,具体解答可以参考下面的代码。
解答
function find(origin) {
return {
data: origin,
where: function(searchObj) {
const keys = Reflect.ownKeys(searchObj)
for (let i = 0; i < keys.length; i++) {
this.data = this.data.filter(item => searchObj[keys[i]].test(item[keys[i]]))
}
return find(this.data)
},
orderBy: function(key, sorter) {
this.data.sort((a, b) => {
return sorter === 'desc' ? b[key] - a[key] : a[key] - b[key]
})
return this.data
}
}
}
题目二
对象的深度比较
// 已知有两个对象obj1和obj2,实现isEqual函数判断对象是否相等
const obj1 = {
a: 1,
c: 3,
b: {
c: [1, 2]
}
}
const obj2 = {
c: 4,
b: {
c: [1, 2]
},
a: 1
}
// isEqual函数,相等输出true,不相等输出false
isEqual(obj1, obj2)
我们知道对象是引用类型,即使看似相同的两个对象也是不相等的
const obj1 = {
a: 1
}
const obj2 = {
b: 1
}
console.log(obj1 === obj2) // false
本题要做的就是判断两个地址不相同的对象是否“相等”,相等的话返回true,否则返回false。本文只给一个参考的解答,实际需要考虑很多方面,可以参考Underscore里的_.isEqual()方法,地址:https://github.com/lessfish/underscore-analysis/blob/master/underscore-1.8.3.js/src/underscore-1.8.3.js#L1094-L1190
解答
// 答案仅供参考
// 更详细的解答建议参考Underscore源码[https://github.com/lessfish/underscore-analysis/blob/master/underscore-1.8.3.js/src/underscore-1.8.3.js#L1094-L1190](https://github.com/lessfish/underscore-analysis/blob/master/underscore-1.8.3.js/src/underscore-1.8.3.js#L1094-L1190)
function isEqual(A, B) {
const keysA = Object.keys(A)
const keysB = Object.keys(B)
// 健长不一致的话就更谈不上相等了
if (keysA.length !== keysB.length) return false
for (let i = 0; i < keysA.length; i++) {
const key = keysA[i]
// 类型不等的话直接就不相等了
if (typeof A[key] !== typeof B[key]) return false
// 当都不是对象的时候直接判断值是否相等
if (typeof A[key] !== 'object' && typeof B[key] !== 'object' && A[key] !== B[key]) {
return false
}
if (Array.isArray(A[key]) && Array.isArray(B[key])) {
if (!arrayEqual(A[key], B[key])) return false
}
// 递归判断
if (typeof A[key] === 'object' && typeof B[key] === 'object') {
if (!isEqual(A[key], B[key])) return false
}
}
return true
}
function arrayEqual(arr1, arr2) {
if (arr1.length !== arr2.length) return false
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) return false
}
return true
}
isEqual(obj1, obj2)
题目三
// 判断JS对象是否存在循环引用
const obj = {
a: 1,
b: 2,
}
obj.c = obj
// isHasCircle函数, 存在环输出true,不存在的话输出false
isHasCircle(obj)
解答
function isHasCircle(obj) {
let hasCircle = false
const map = new Map()
function loop(obj) {
const keys = Object.keys(obj)
keys.forEach(key => {
const value = obj[key]
if (typeof value == 'object' && value !== null) {
if (map.has(value)) {
hasCircle = true
return
} else {
map.set(value)
loop(value)
}
}
})
}
loop(obj)
return hasCircle
}
这三道题目其实都是js基础的考察,能够写好非常加分,第二题和第三题其实也是类似的,类似的题目还有对象的深拷贝等,答案并不唯一,上面给的答案也并不是完全正确的,还有很多细节需要优化,所以平时还是得多积累多写。
内推社群
我组建了一个氛围特别好的腾讯内推社群,如果你对加入腾讯感兴趣的话(后续有计划也可以),我们可以一起进行面试相关的答疑、聊聊面试的故事、并且在你准备好的时候随时帮你内推。下方加 winty 好友回复「面试」即可。