Skip to content
目录

前端判断数据类型

  1. typeof

    对象({})、数组([])、null 的结果都是 object

    新数据类型如 Symbol、BigInt,无法识别

  2. instanceof

    无法判断基本数据类型和 null

  3. Object.prototype.toString.call()

    语法相对复杂,但是可以区分数组、函数等引用数据类型

  4. Array.isArray()

    只能判断数组类型,精准判断数组

typeof 和 instanceof 的区别:

返回值类型:typeof 返回一个表示数据类型的字符串,instanceof 返回一个布尔值,表示是否是指定类的实例

判断范围:typeof 相对来说可以判断的类型更多,instanceof 只能用来判断对象类型(也就是两者互补)。

精确性:typeof 对基本数据类型判断比较精确,对于引用类型则无法进一步区分。instanceof 可以准确的判断引用类型。

防抖和节流

防抖

防抖是指在用户事件被触发 n 秒后再执行回调逻辑,如果在这 n 秒内事件再次被触发,则重新计时。换言之,程序只执行最后一次触发事件,以此来优化性能。

实现代码:

js
const debounce = (fn, delay) => {
    let timer = null;
    return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => {
            fn(args);
        }, delay);
    };
};

节流

节流是指当遇到连续用户事件时,以 n 秒为间隔进行阻断,目的是减少同一时间段内连续事件的触发频率,以此来提升性能。

实现代码:

js
const trottle = (fn, delay) => {
    let timer = null;
    return function (...args) {
        if (timer) return;
        timer = setTimeout(() => {
            fn(args);
            clearTimeout(timer);
            timer = null;
        }, delay);
    };
};

![image-20240312192537719](/Users/fiat_lux/Library/Application Support/typora-user-images/image-20240312192537719.png)

深拷贝

JSON.parse(JSON.stringify(obj))

缺点:JSON.stringify() 会丢失部分属性

关于 key 为 Symbol 的会忽略掉,值为 undefined 的会忽略掉,NaN 变成 null,函数会忽略掉,Infinity 会变成 null

总结来说:

无法复制函数和 undefined;

如果对象中包含循环引用,会抛出错误;

对于包含 Symbol、RegExp 等特殊类型的对象,可能无法正确工作

js
const obj = {
    [Symbol.for('key1')]: 'a',
    b: undefined,
    c: NaN,
    d: () => {
        return null;
    },
    e: Infinity,
    f: null,
};
console.log(JSON.parse(JSON.stringify(obj))); // {c: null, e: null, f: null}

![image-20240305135515117](/Users/fiat_lux/Library/Application Support/typora-user-images/image-20240305135515117.png)

使用 js 工具库 lodash

js
const obj = { a: 1, b: 2, c: 3 };
const newObj = _.cloneDeep(obj);

递归复制

js
function deepClone(obj) {
    // 先判断 obj 的数据类型
    if (obj === null) return obj; // obj 为 null
    if (obj instanceof Date) return new Date(obj); // obj 为 Date
    if (obj instanceof RegExp) return new RegExp(obj); // obj 为 RegExp
    if (typeof obj !== 'object') return obj;
    let cloneObj = new obj.constructor();
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            // 实现一个递归拷贝
            cloneObj[key] = deepClone(obj[key]);
        }
    }
    return cloneObj;
}

扩展:

JSON.stringify(value, replacer, space)

参数一:value 表示要被序列化的对象,接受对象或数组类型

参数二:replacer 用于标记需要序列化的属性,接受数组和函数类型

参数三:space 用于描述序列化后的缩进字符数,用于美化格式

使用场景:

  1. localStorage 的存储

​ localStorage 只能存储字符串类型,kv(key,value) 结构

js
const obj = { a: 1, b: 2, c: 3 };
// 序列化要存储的数据: JSON.stringify(obj)
// 存储
localStorage.setItem('obj', JSON.stringify(obj));
// 取出
localStorage.getItem('obj'); // '{"a":1,"b":2,"c":3}'
// 移除
localStorage.removeItem('obj');
  1. 对象的深拷贝

    js
    const obj = { a: 1, b: 2, c: 3 };
    const objA = obj;
    const objB = JSON.parse(JSON.stringify(obj));
    // 修改
    objA.a = 11;
    console.log(obj); // {a: 11, b: 2, c: 3}
    console.log(objA); // {a: 11, b: 2, c: 3}
    
    objB.a = 123;
    console.log(obj); // {a: 11, b: 2, c: 3}
    console.log(objB); // {a: 123, b: 2, c: 3}
  2. 删除对象属性

    js
    const obj = { a: 1, b: 2, c: 3 };
    const str = JSON.stringify(obj, (key, value) => {
        if (key === 'b') {
            return undefined;
        }
        return value;
    });
    console.log(str); // '{"a":1,"c":3}'
    const objA = JSON.parse(str);
    console.log(objA); // {a: 1, c: 3}

前端跨域

跨域是前端解决的范畴

什么时候会发生跨域

跨域是由于浏览器的同源策略(协议、域名、)所导致的,是发生在 页面 到 服务端 请求的过程中

项目中怎么解决这个跨域问题的

  1. Nginx 反向代理
  2. 搭建 BFF 层

了解后端处理跨域的原理吗

可以使用 nginx,但是我们项目后端是在微服务中处理跨域

cookie 和 localStorage 的区别

项目中的登录是用的 cookie 还是 localStorage 来保存 token 的?

cookie

用户在浏览器这边进行登录接口请求,服务端收到这个请求之后,在用户名和密码都正确的情况下,服务器在向浏览器返回登录结果的时候,会生成一个 cookie,并且在 Http Response Header 中 Set-Cookie。这样,当浏览器再次请求服务端时,都会同步的带上 cookie,cookie 会附带在每个 Http 请求上。

生成机制

  1. 服务端生成,在 Http Response Header 中 Set-Cookie (我们项目中就是使用的这种)

  2. 客户端生成,通过 document.cookie 设置

Cookie 设置初衷是用于维持 HTTP 状态,不用于存储数据。因此 cookie 有以下缺点:

  1. 大小限制:每个 cookie 项只能存储 4K 数据
  2. 性能浪费: cookie 附带在 http 请求上,数据量过大,会导致每个 http 请求就非常庞大,会很消耗流量和带宽。

前端和后端是同一个域名吗?

那肯定不是同一个

接口请求也是不一样的,所以跨域了

react

常用的一些 hooks

useEffect 和 useLayoutEffect 的区别?谁先执行?谁后执行?

react 使用 虚拟 dom 的好处?为什么会提高性能?

直接操作 dom 性能是最高的。

react diff 的原理

Promise 解决了什么问题

Promise 的出现最重要的是为了统一 JS 中的异步实现方案

异步是 JS 中的常见场景,统一实现方案,不仅可以有效降低心智负担,更重要的是可以让不同的异步场景相互联动

Promise 也无法消除回调地狱,它只不过通过链式调用的方式让回调变得可控

什么是 Vue 的响应式

vue 数据响应式设计的初衷是为了实现数据和函数的联动,当数据变化时,用到该数据的联动函数会自动重新运行

具体在 vue 的开发中,数据和组件的 render 函数关联在一起,从而实现了数据变化自动运行 render,在感官上就看到了组件的重新渲染。

除了 vue 自动关联的 render 函数,其他还有很多使用到 vue 响应式的场景,比如 computed、watch 等等,不能仅把 vue 的数据响应式想象成和 render 的关联