阿里笔试题:链式调用、对象比较以及对象是否存在循环引用

最近小伙伴参加了阿里的面试,其中有一轮就是笔试环节,面试官就给小伙伴出了三道笔试题,废话不多说我们来看看是哪三道题目吧。

题目一

// 实现一个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)

循环引用的判断我们可以通过map来进行暂存,当值是对象的情况下,我们将对象存在map中,循环判断是否存在,如果存在就是存在环了,同时进行递归调用。 具体解答可以参考下面的代码。

解答

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 好友回复「面试」即可。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值