【前端面试小册】JS-第26节:实现 add 链式调用(百度一面)

第26节:实现 add 链式调用(百度一面)

一、题目描述

1.1 需求

实现一个 add 函数,支持链式调用:

add(1).add(2).add(3)  // 等于 6

1.2 分析

要实现链式调用,需要满足以下条件:

  1. 函数可以链式调用:那么函数执行完肯定要返回 this 才行
  2. 函数原型上必须有 add 函数:才可使用 .add

二、实现思路

2.1 核心思路

  • 创建一个构造函数 _add,用于存储累加值
  • 在构造函数原型上添加 add 方法
  • add 方法返回 this,支持链式调用
  • 提供一个工厂函数 add,返回 _add 的实例

2.2 实现代码

function _add(num) {
    this.sum = 0;
    this.sum += num;
    return this;
}

_add.prototype.add = function(num) {
    this.sum += num;
    return this;
};

function add(num) {
    return new _add(num);
}

// 测试
let res = add(1).add(2).add(3);
console.log(res.sum);  // 6

2.3 执行流程

graph TD
    A[调用 add 1] --> B[创建 _add 实例]
    B --> C[sum = 1]
    C --> D[返回 this]
    D --> E[调用 add 2]
    E --> F[sum = 3]
    F --> G[返回 this]
    G --> H[调用 add 3]
    H --> I[sum = 6]
    I --> J[返回 this]
    J --> K[访问 sum 属性]

三、优化版本

3.1 支持获取结果

function _add(num) {
    this.sum = num || 0;
    return this;
}

_add.prototype.add = function(num) {
    this.sum += num;
    return this;
};

// 添加 valueOf 和 toString 方法,支持直接获取值
_add.prototype.valueOf = function() {
    return this.sum;
};

_add.prototype.toString = function() {
    return String(this.sum);
};

function add(num) {
    return new _add(num);
}

// 测试
let res = add(1).add(2).add(3);
console.log(res.sum);      // 6
console.log(+res);         // 6(通过 valueOf)
console.log(String(res));  // "6"(通过 toString)

3.2 支持减法

function _add(num) {
    this.sum = num || 0;
    return this;
}

_add.prototype.add = function(num) {
    this.sum += num;
    return this;
};

_add.prototype.subtract = function(num) {
    this.sum -= num;
    return this;
};

_add.prototype.valueOf = function() {
    return this.sum;
};

function add(num) {
    return new _add(num);
}

// 测试
let res = add(10).add(5).subtract(3);
console.log(res.sum);  // 12

3.3 支持链式调用和直接计算

function _add(num) {
    this.sum = num || 0;
    return this;
}

_add.prototype.add = function(num) {
    this.sum += num;
    return this;
};

_add.prototype.valueOf = function() {
    return this.sum;
};

function add(num) {
    if (this instanceof _add) {
        // 如果已经是指定实例,直接调用 add 方法
        return this.add(num);
    }
    // 否则创建新实例
    return new _add(num);
}

// 测试
let res1 = add(1).add(2).add(3);
console.log(res1.sum);  // 6

let res2 = add(10).add(20);
console.log(res2.sum);  // 30

四、完整实现(支持更多操作)

function Calculator(initialValue = 0) {
    this.value = initialValue;
}

Calculator.prototype.add = function(num) {
    this.value += num;
    return this;
};

Calculator.prototype.subtract = function(num) {
    this.value -= num;
    return this;
};

Calculator.prototype.multiply = function(num) {
    this.value *= num;
    return this;
};

Calculator.prototype.divide = function(num) {
    if (num === 0) {
        throw new Error('Division by zero');
    }
    this.value /= num;
    return this;
};

Calculator.prototype.valueOf = function() {
    return this.value;
};

Calculator.prototype.toString = function() {
    return String(this.value);
};

// 工厂函数
function add(num) {
    return new Calculator(num);
}

// 测试
let res = add(10)
    .add(5)
    .subtract(3)
    .multiply(2)
    .divide(4);
console.log(res.value);  // 6
console.log(+res);       // 6

五、测试用例

5.1 基础测试

// 测试 1:基本链式调用
let res1 = add(1).add(2).add(3);
console.log(res1.sum);  // 6

// 测试 2:单个值
let res2 = add(5);
console.log(res2.sum);  // 5

// 测试 3:零值
let res3 = add(0).add(0);
console.log(res3.sum);  // 0

5.2 边界情况

// 测试 4:负数
let res4 = add(10).add(-5);
console.log(res4.sum);  // 5

// 测试 5:小数
let res5 = add(1.5).add(2.3);
console.log(res5.sum);  // 3.8

// 测试 6:多次调用
let res6 = add(1).add(2).add(3).add(4).add(5);
console.log(res6.sum);  // 15

六、扩展思考

6.1 支持延迟计算

function _add(num) {
    this.operations = [{ type: 'add', value: num }];
    return this;
}

_add.prototype.add = function(num) {
    this.operations.push({ type: 'add', value: num });
    return this;
};

_add.prototype.subtract = function(num) {
    this.operations.push({ type: 'subtract', value: num });
    return this;
};

_add.prototype.value = function() {
    return this.operations.reduce((sum, op) => {
        if (op.type === 'add') {
            return sum + op.value;
        } else {
            return sum - op.value;
        }
    }, 0);
};

function add(num) {
    return new _add(num);
}

// 测试
let res = add(1).add(2).subtract(1);
console.log(res.value());  // 2

6.2 支持链式调用和直接计算

function _add(num) {
    this.sum = num || 0;
    return this;
}

_add.prototype.add = function(num) {
    this.sum += num;
    return this;
};

_add.prototype.valueOf = function() {
    return this.sum;
};

function add(num) {
    return new _add(num);
}

// 测试:支持直接参与计算
let result = add(1).add(2).add(3) + 10;
console.log(result);  // 16

七、面试要点总结

核心知识点

  1. 链式调用原理:方法返回 this
  2. 原型方法:在构造函数原型上添加方法
  3. 工厂函数:提供便捷的创建方式
  4. valueOf/toString:支持隐式类型转换

常见面试题

Q1: 如何实现链式调用?

答:在方法中返回 this,这样就可以连续调用多个方法。

Q2: 如何让对象支持直接参与计算?

答:实现 valueOftoString 方法,支持隐式类型转换。

Q3: 如何优化 add 函数?

答:可以添加 valueOftoString 方法,支持更多操作(加减乘除),支持延迟计算等。

实战建议

  • ✅ 理解链式调用的实现原理
  • ✅ 掌握原型方法的使用
  • ✅ 理解 valueOftoString 的作用
  • ✅ 能够扩展功能(支持更多操作)
#前端##百度##字节##腾讯##前端面试#
前端面试小册 文章被收录于专栏

每天更新3-4节,持续更新中... 目标:50天学完,上岸银行总行!

全部评论

相关推荐

lz bg 双2,求职方向前端,一段大厂实习注:红黑榜都是按个人经历来排,比较主观但真实黑榜:北森:1. 大部分公司的测评都是源自于北森,题都差不多,成绩又不共享,秋招花了很多时间重复做北森测评,yue了2. 投递北森,给了个巨多内容的测评,做完后测评挂科大讯飞:一面面试官跟我说,你属于比较冷静的那种人(想说lz比较内向?),我们更倾向于招热情的校招生。但还是进二面了,二面面试官全程黑脸加打断,反问环节一脸不耐烦。问后续流程是什么,非常不耐烦的说,后续就是我们这轮面试结束了。阿里系:淘天,钉钉,虎鲸文娱,阿里系更是重量级,其他很多部门都是测评笔试都做但是不约面,可能是lz学历不够,也可能因为阿里用react而lz用的是vue。虎鲸文娱先约面,然后又马上单方面邮件取消面试,然后很长时间没有消息,然后官网评估挂淘天:面试官不开摄像头,多次打断,最逆天的是做手撕的时候面试官说自己去忙半小时,退出面试间,让我自己做完退出。八股+手撕都对,第二天秒挂钉钉:最重量级的来了,面试官迟到十分钟,不开摄像头,面试时长二十分钟。最后反问多久出结果,告诉我招聘已经接近尾声了,很快出结果。第二天挂。纯纯KPI浪费时间。柠檬微趣:牛客问我要简历,我给了,显示初筛通过,没后续。boss上hr问我要简历,给了后发笔试题,笔试ak做完后问hr,hr也不告诉笔试是否通过,直接回我“感谢投递,正在寻找其他背景的人”。既然不想约面,为什么又要简历又发笔试呢,祝早日被鸽穿。华睿(说是浙江大华子公司):最不专业的一集,一面二面根本不约面试时间,直接打电话突袭面试。hr面更是对方疯狂卡顿,而且表示后续会是总监给我打电话?(贵公司这么喜欢打电话吗?而且也是不约时间随时打给我的意思)红榜:联友科技:嫡长offer,虽然网上名声不太好,但是一面给offer,一面面试官甚至是同校学长,价格也还比较有诚意,给了秋招中的lz很大信心,红榜。快手:三次面试面试官人都不错,反问时给的建议都比较中肯,流程推进很快,虽然泡了很久池子,但是开奖薪资也很不错。红。小红书:面试官很务实,直接讲明业务是什么,包括平时工作作息和强度。面试流程推进很快,开奖薪资也很高。红。沐瞳科技:虽然前两面面试官不开摄像头+面试体验一般,hrbp感觉是劲劲的压力面,开奖薪资一般。但是三面总监面是秋招面试体感最好的,聊了部门倾向,喜欢打什么游戏,根据游戏分析性格,聊部门未来规划以及个人未来规划。红。京东:两轮技术面无手撕无八股,面试官人比较友善,线下hr面体验也还不错,但是仍在泡池子,期待和东子做兄弟。滴滴:一面面试官全程微笑,非常友善,结束后马上二面。二面面试官问的都是开放性问题,面试氛围很友好,反问环节也耐心解答分析问题,最重视反问的一次。本来以为没有三面挂了,但是发邮件后才确认原来已经在跑池子,期待滴滴的965上面只是部分公司总结,有些公司体验感觉红黑都不合适,这里就只放比较好或差的.欢迎大家一起讨论秋招体验.
秋招吐槽大会
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务