之前写过js类型转换,https://blog.csdn.net/Y_G_G/article/details/78031510 是比较详细的规则,可能后面工作中用得多了,现在并不太注意这些。最近看了一篇文章,https://juejin.im/entry/58beb514128fe1006456df73 让我更深刻的认识了类型转换,尤其是对象类型转换.,以及看问题的本质。
个人觉得,记住具体的规则,去看红宝书就可以了。书上写的详细又具体。
问题引入
这篇文章 以一道面试题开始:
// 实现一个函数,运算结果可以满足如下预期结果:
add(1)(2) // 3
add(1, 2, 3)(10) // 16
add(1)(2)(3)(4)(5) // 15
给出的答案是:
function add () {
var args = Array.prototype.slice.call(arguments);
var fn = function () {
var arg_fn = Array.prototype.slice.call(arguments);
return add.apply(null , args.concat(arg_fn));
}
fn.valueOf = function () {
return args.reduce(function (a, b) {
return a + b;
})
}
return fn;
}
问题分析
求和运算,链式调用,参数不定。
- 猜测 会用到高阶函数 reduce 实现累加。
- 调用add()的时候,如何既返回一个值又返回一个函数供后续调用?
// reduce进行累加
arr.reduce((a,b) => {
return a+b;
})
function add() {
var args = Array.prototype.slice.call(arguments);
var fn = function() {
}
return fn;
}
Array.prototype.slice.call(arguments) 能将具有length属性的对象转成数组。
因为arguments并不是真正的数组对象,只是与数组类似,并没有slice这个方法,而Array.prototype.slice.call(arguments)可以理解成是让arguments转换成一个数组对象,让arguments具有slice()方法。直接写arguments.slice()会报错。
问题深入
function的转换
function test() {
console.log(10);
}
test
// ƒ test() {
console.log(10);
}
test()
// 10
执行test和 test() 返回不同的结果。执行 test 会自行调用了函数的 valueOf 方法
下面重写 valueOf
test.valueOf = function() {
console.log('调用 valueOf 方法');
return 20;
}
test
// 调用 valueOf 方法
// 20
解决问题
让fn 拿到所有参数组成的数组,让数组做最后的累加。还是个闭包  ̄□ ̄
延伸 - 对象的转换
ToPrimitive:
- 当对象类型需要被转为原始类型时,先查找对象的valueOf方法,如果valueOf方法返回原始类型的值,则ToPrimitive的结果就是这个值;
- 如果valueOf不存在或者valueOf方法返回的不是原始类型的值,会调用对象的toString方法,会遵循对象的ToString规则,并toString的返回值作为ToPrimitive的结果。
简言之,一般对象先调用valueOf,有原始类型就返回,没有便继续找toString方法。(date 就先调toString)
var obj = {
toString: function() {
console.log('调用了 obj.toString');
return 11;
},
valueOf: function() {
console.log('调用了 obj.valueOf')
return {};
}
}
var a = 88- obj
//调用了 obj.valueOf
//调用了 obj.toString
//77