持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第27天,点击查看活动详情
在写代码的时候很经常遇到一个情况,就是觉得自己所有的思路和代码是正确的,但是结果就是不正确,甚至有的时候是抄别人的代码都抄不明白,往往都是在一些代码边界出现问题,以及一些相似代码处,跟多的时候是代码书写的时候把单词写错了,我印象最深的就是把数组的length属性写成了lenght然后找了半天,今天要分享一个自己稀里糊涂的小错误,这个错误也是由于写快了。
题目要求:求出矩阵连乘所需要的最少次数:
我的代码:
let p = [30, 35, 15, 5, 10, 20, 25];
let m = new Array(p.length)
.fill()
.map(() => new Array(p.length).fill(Infinity));
function matrixChain() {
let n = p.length - 1;
for (let i = 1; i <= n; i++) {
for(let j=1;j<=n;j++){
if(i===j){
m[i][j]=0;
}else{
m[i][j]=Infinity;
}
}
}
for (let i = n; i >= 1; i--) {
for (let j = 1; j <= n; j++) {
for (let k = i; k < j; k++) {
m[i][j] = Math.min(
m[i][j],
m[i][k] + m[k + 1][j] + p[i - 1] * [k] * p[j]
);
}
}
}
}
matrixChain();
console.log(m[2][5]);
正确答案
let p = [30, 35, 15, 5, 10, 20, 25];
let m = new Array(p.length)
.fill()
.map(() => new Array(p.length).fill(Infinity));
function matrixChain() {
let n = p.length - 1;
for (let i = 1; i <= n; i++) {
for(let j=1;j<=n;j++){
if(i===j){
m[i][j]=0;
}else{
m[i][j]=Infinity;
}
}
}
for (let i = n; i >= 1; i--) {
for (let j = 1; j <= n; j++) {
for (let k = i; k < j; k++) {
m[i][j] = Math.min(
m[i][j],
m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j]
);
}
}
}
}
matrixChain();
console.log(m[2][5]);
相信如果眼不是很尖的同学是发现不了不同的,但是二者跑出的结果确实不一样的,所以我写了for循环进行逐个比较原理是在数组相乘的地方少了数组名:p[i - 1] * p[k] * p[j]被我写成了p[i - 1] * [k] * p[j]。
问题产生原因
手速过快写错了,但是对于这个结果我不是很满意。为什么你这不报错呢?一个数组乘以一个数字,你这不合理呀,这应该给我报个红这样我不就好找了。想到这里我的脑海里就出现了犀牛书中的隐式类型转换。我猜测了一下过程,应该是js解析引擎发现我要用一个数组和一个number类型进行相乘,那么它会常识着进行类型转化,那么数组应该会调用响应的toString()方法,而这个数组恰好只有一个元素,那么调用toString的时候,就变成了字符k,后为了能和数字进行相乘所以再次进行隐式类型转换,变成数字,所以没有报错。
查阅资料
我马上翻阅犀牛书,在对象方法的时候其实就有对其的介绍:toString方法没有参数,它将返回一个调用这个方法的对象值的字符串,javaScript会调用这个方法,比如在使用+运算符连接一个字符串和一个对象的时候或者在希望使用字符串的方法中使用了对象时都会调用这个方法。默认的toString方法的返回值带有的信息量是很少的,所以很多类都有自定义的toString方法例如数组转换为字符串的时候,得到是一个数组元素的列表。只是每个元素都转化为了字符,函数转化为字符串的时候是其源代码。
看到这里其实就明白了其实我的猜想是正确的,确切的说不是猜想,毕竟犀牛书我看过了,只不过是残留的记忆是正确的。
其他
其实toString方法还有一个重要的作用,那就是判断一个变量是什么类型,需要注意我们要使用的是object的toString,因为正如其说的很多类其实都对toString进行了重写,我们来看下对象的toString调用是怎么样的:
console.log(Object.prototype.toString.call({}))
console.log(Object.prototype.toString.call([]))
console.log(Object.prototype.toString.call(1))
console.log(Object.prototype.toString.call(""))
console.log(Object.prototype.toString.call(true))
输出
[object Object]
[object Array]
[object Number]
[object String]
[object Boolean]