【前端面试小册】JS-第26节:实现 add 链式调用(百度一面)
第26节:实现 add 链式调用(百度一面)
一、题目描述
1.1 需求
实现一个 add 函数,支持链式调用:
add(1).add(2).add(3) // 等于 6
1.2 分析
要实现链式调用,需要满足以下条件:
- 函数可以链式调用:那么函数执行完肯定要返回
this才行 - 函数原型上必须有
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
七、面试要点总结
核心知识点
- 链式调用原理:方法返回
this - 原型方法:在构造函数原型上添加方法
- 工厂函数:提供便捷的创建方式
- valueOf/toString:支持隐式类型转换
常见面试题
Q1: 如何实现链式调用?
答:在方法中返回 this,这样就可以连续调用多个方法。
Q2: 如何让对象支持直接参与计算?
答:实现 valueOf 和 toString 方法,支持隐式类型转换。
Q3: 如何优化 add 函数?
答:可以添加 valueOf 和 toString 方法,支持更多操作(加减乘除),支持延迟计算等。
实战建议
- ✅ 理解链式调用的实现原理
- ✅ 掌握原型方法的使用
- ✅ 理解
valueOf和toString的作用 - ✅ 能够扩展功能(支持更多操作)
前端面试小册 文章被收录于专栏
每天更新3-4节,持续更新中... 目标:50天学完,上岸银行总行!

查看4道真题和解析