读《前端面试突破:JavaScript》

91 阅读4分钟

读:《前端面试突破:JavaScript》

最近在准备面试,也算是重新学习一下,本书出自于leetcod,这篇文章就是记录一下阅读中遇到的问题或困惑

问题记录

  • 1. 数字0.1对应的二进制是什么?需要深入学习IEEE 754 标准的双精度 64 位格式

    详细内容

  • 2. 学到了??=||=&&=运算符

  • 3. typeof null的值为object这个bug是如何产生的?学习不同值类型的类型标签

在最初的js实现中,javascript的存储由类型标签+值,其中object的类型标签为000null的类型标签也是000。typeof在校验类型时,参照的便是类型标签,所以会由此误认为是object

  • 4. instanceof实现原理?手写instanceof实现。
简单例子
    function instanceOf(left, right) {
        if (typeof left !== "object" || left === null) {
            return false;
        }

        let proto = Reflect.getPrototypeOf(left);

        while (proto) {
            if (proto === right.prototype) {
                return true;
            }
            proto = Reflect.getPrototypeOf(proto);
        }

        return false;
    }
  • 5. 作用域分类:全局、函数、块级、模块

  • 6. js中数据存储的方式,堆和栈具体是什么?

主要是想要写一段代码去模拟变量存储到堆和栈,以及从堆和栈中取出的操作。这里还需要考虑执行上下文和作用域链,暂时还没有找到相关的详细资料,所以先不写。

  • 7. 手写一下基于原型的继承方式?
简述
其实也没啥好写的,就在这里简述一下:

原型链继承:
`SubType.prototype = new SuperType()`
将父类型的一个实例作为子类型的`prototype`

盗用构造函数:就是在子类函数中调用`SuperType.call(this)`

组合继承:就是将`原型链``盗用构造函数`两个相结合

寄生式继承:其实就是`Object.create`方法

寄生组合式继承: 
子类函数中通过`盗用构造函数`模式获取父类的实例属性,
子类的`prototype`设置为`Object.create(SuperType.prototype)`
  • 8. 手写一下使用WeakMap实现类的私有属性?
简单例子
    /** 存放name私有属性的weakMap */
    const nameVm = new WeakMap();

    class Book {
        constructor() {
            // 初始化name私有属性
            nameVm.set(this, "book");
        }
        // 获取name
        getName() {
            return nameVm.get(this);
        }
        // 设置name
        setName(name) {
            nameVm.set(this, name);
            return true;
        }
    }
  • 9. bind手写实现中为啥要new F并将其作为新bound函数的prototype

它这里主要是为了判断是不是在new创建对象,在new创建时,bind传入的第一个对象将被忽略

  • 10. 箭头函数不能绑定this,没有arguments,也不能new

确实不能new,但是不能说没有arguments,它的argumentsthis一样,是箭头函数所在的arguments

  • 11. 手写一下节流的两种实现模式,定时器和时间戳模式
定时器模式
    
    // 时间戳模式
    const throttle = (fn, time) => {
        let able = true;
        return (...args) => {
            if (able) {
                able = false;
                fn(...args);
                setTimeout(() => {
                    able = true;
                }, time);
            }
        };
    };
    
时间戳模式
    
    // 时间戳模式   
    const throttle = (fn, time) => {
        let able = true;
        let lastDateTime = 0;
        return (...args) => {
            const now = Date.now();
            if (now - lastDateTime > time) {
                able = false;
                lastDateTime = now;
                fn(...args);
            }
        };
    };
    
  • 12. 手写一下Promise实现
极简版本
    
    class MyPromise {
        constructor(func) {
            this.state = "pending";
            this.value = undefined;
            this.resolvedCbs = [];
            func(this.resolve.bind(this));
        }
        resolve(value) {
            if (this.state === "pending") {
                this.state = "resolved";
                this.value = value;
                const onResolve = this.resolvedCbs.shift();
                if (onResolve) {
                    onResolve(value);
                }
            }
        }
        then(onResolve) {
            return new MyPromise((resolve) => {
                if (onResolve) {
                    if (this.state === "pending") {
                        this.resolvedCbs.push((value) => {
                            resolve(onResolve(value));
                        });
                    } else if (this.state === "resolved") {
                        resolve(onResolve(this.value));
                    }
                } else {
                    resolve(undefined);
                }
            });
        }
    }
    
  • 13. 手写一个可迭代for of的简单类
简单例子
    class Forof {
        constructor(limit) {
            this.index = 0;
            this.limit = limit;
        }
        [Symbol.iterator]() {
            return this;
        }
        next() {
            const res = { done: true, value: undefined };
            if (this.index < this.limit) {
                res.done = false;
                res.value = this.index;
                this.index++;
            }
            return res;
        }
    }
  • 14. 手写一个*函数,并练习yieldyield*
简单例子
    
    function* forof(limit) {
        let index = 0;
        while (index < limit) {
            yield index;
            index++;
        }
    }

    function* forofArr(limit) {
        const arr = new Array(limit).fill(0).map((_, i) => i);
        yield* arr;
    }
    
  • 15. await可以获取thenable对象的值,如下例
简单例子
const a = {
  then(cb) {
    setTimeout(() => {
      cb(1);
    }, 1000);
  },
};

(async function () {
  const res = await a;
  console.log("res", res);
})();
  • 16. 学习一下eval方法
简单示例
// 可以获取脚本结果
const a = eval("2+2");

console.log("a", a);

// 模拟脚本,使用window对象
const script = "window.a = 1;console.log(window.a)";
// 定义window对象
const window = {};
// 调用脚本,脚本中可以获取本地的window对象
eval(`(function(window){${script}})(window)`);

console.log(eval([1, 2]));

// 非直接调用方式,脚本作用域在全局,不在当下
eval?.("console.log(window.a)");
  • 17. 执行上下文和作用域链

这里的想法是通过代码模拟执行上下文和作用域链,如有幸学习到相关的内容再说。

  • 18. 引用回收机制有循环引用的问题,标记清除有分代、增量和闲时收集三个优化策略

  • 19. 研究一下怎么才能触发内存泄漏,目前是发现console.log会发生内存泄漏

简单例子
    <body>
        <div id="hallo">这是好的</div>
        <script>
            var theThings = [];
            var replaceThing = function () {
                theThings.push(
                    new Array(Math.floor(Math.random() * 1000000)).join("*")
                );
                // console.log("theThings.length", theThings);
            };
            setInterval(replaceThing, 1000);
            document.getElementById("hallo").addEventListener("click", () => {
                for (let n of theThings) {
                    console.log(n);
                }
            });
        </script>
    </body>
  • 20. 学习一下indexDB的用法
  • 21. 学习一下Reflect的方法
  • 22. 学习一下requirejsseajs
  • 23. 实现一下大文件上传
  • 24. 学习和实现一下单点登录