手写代码系列

手写代码系列

三月 10, 2021

手写一个instanceof

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function myInstanceof (obj, target) {
let res = false;
let tempObj = obj;
while(tempObj.__proto__) {
if(tempObj.constructor === target) {
res = true;
}
tempObj = tempObj.__proto__;
}
return res;
}

class Animal {}

class Dog extends Animal {}

const husky = new Dog();

console.log(husky instanceof Animal);

console.log(myInstanceof(husky, Animal))

console.log(Animal instanceof Animal);

console.log(myInstanceof( Animal, Animal ))

__proto__可以用Object.getPrototypeof()代替。因为前者不是标准方法,是浏览器自己实现的。

手写斐波那契数列

很经典的问题,斐波那契数列的意思是:第一位为1、第二位为1、第n位为前两项之和。

递归

所以最符合思路的就是递归。

function fibo(n) {

      if (n === 1) return 1;
      if (n === 2) return 1;
    // 结果是前两项之和。
      return fibo(n - 2) + fibo(n - 1);
}

然后就会扯到、递归的危害和优化,危害当然是堆栈过多。而且有个规律是,尾递归是肯定可以优化的。以上代码就是个经典的尾递归。就是递归方法的调用在方法的最后。

尾递归为啥能优化?

函数栈的目的是啥?是保持入口环境。那么在什么情况下可以把这个入口环境给优化掉?答案不言而喻,入口环境没意义的情况下为啥要保持入口环境?尾递归,就恰好是这种情况。

尾递归保存的状态再递归执行完成后立马被返回,没有意义。

循环

一般思路下,尾递归可以用循环的方式替代

而这就没必要用什么固定思路去转换了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function fibo(n) {
if (n === 1) return 1;
if (n === 2) return 1;

let sum = 0;
let n1 = 1;
let n2 = 1;

for (let i = 2; i < n; i++) {

sum = n1 + n2;

n1 = n2;
n2 = sum;

}

return sum;

}

思路是。一个for循环,sum值是前两项的和,则需要两个变量存储前两项的和。n1、n2

每次i递增。则把n1丢弃、n1 = n2、n2 = sum即可。