个人查缺补漏记录

50 阅读4分钟

1、强缓存和协商缓存

强缓存:

  •  cache-control (HTTP/1.1):如  max-age=3600  表示缓存 3600 秒; no-cache 不直接用缓存,需验证; no-store 不缓存。
  •  expires (HTTP/1.0):如  expires: Wed, 29 Feb 2024 12:00:00 GMT ,但逐渐被  cache-control  替代,可同时设置以兼容旧版。

协商缓存:

  •  etag 和 if-none-match :服务器生成 etag ,浏览器携带 if-none-match 验证。
  •  last-modified 和 if-modified-since :服务器设置 last-modified ,浏览器携带 if-modified-since 验证。

设置方式因服务器和语言而异。通常结合使用以优化性能,静态资源设强缓存,常更新资源用协商缓存。

2、CSRF(跨站请求伪造)和(XSS跨站脚本攻击)

CSRF(跨站请求伪造)和 XSS(跨站脚本攻击)是常见的 Web 安全漏洞,以下是一些常见的防范措施:

CSRF 攻击防范:

1. 验证请求来源:通过在请求中添加不可预测的令牌(token),并在服务器端验证该令牌,确保请求来自合法的源。

2. 限制请求方法:对于敏感操作,只允许使用安全的请求方法(如 POST),而不允许使用容易被伪造的请求方法(如 GET)。

3. 检查 Referer 头:虽然不可完全依赖,但可以检查请求的 Referer 头来判断请求是否来自预期的源。

4. 双重认证:例如结合密码和短信验证码等方式进行重要操作的认证。

XSS 攻击防范:

1. 输入验证和过滤:对用户输入的数据进行严格的验证和过滤,去除可能的恶意脚本代码。

2. 输出编码:在将用户输入的数据输出到页面时,进行适当的编码,如 HTML 编码,以防止脚本被执行。

3. 设置 HTTP 响应头:设置  Content-Security-Policy  等 HTTP 响应头来限制页面能够加载的资源和执行的脚本。

4. 避免直接使用用户输入拼接 HTML:尽量使用模板引擎或安全的方法来构建页面。

这些防范措施需要综合运用,以最大程度地降低 CSRF 和 XSS 攻击的风险,保障 Web 应用的安全性。

3、TS type  和  interface区别

在 TypeScript 中, type  和  interface  有以下一些区别:

1. 扩展方式:

  •  interface  通过继承来扩展,使用  extends  关键字。

  •  type  使用交叉类型( & )来组合类型实现类似扩展的效果。 2. 重复定义:

  • 多次定义同名的  interface  会自动合并其成员。

  • 重复定义同名的  type  会导致错误。 3. 定义联合类型和交叉类型:

  •  type  更适合定义联合类型和交叉类型。 4. 计算属性:

  •  type  可以使用计算属性来创建新类型。 5. 声明合并:

  •  interface  支持声明合并,即可以多次声明同一个接口来添加新的成员。

  •  type  不支持声明合并。

总的来说, interface  更常用于定义对象的形状,而  type  在定义复杂类型和类型运算时更加灵活。具体使用哪种方式取决于具体的场景和需求。

4、手写题

解析urlparams

// '?a=1&a=2&b=3&c=4'
function formatQuery(query = '') {
    const searchParams = new URLSearchParams(query.slice(1))
    const result = {}
    for (const [key, value] of searchParams) {
        if (result[key]) {
            if (Array.isArray(result[key])) {
                result[key].push(value)
            } else {
                result[key] = [result[key], value]
            }
        } else {
            result[key] = value
        }
    }
    return result
}

// 合并两个有序数组并排序,不能先合并在排序

// [1,3,5,7]
// [2,4,6,8]
function mergeSort(arr1, arr2) {
    let i = 0, j = 0, mergeArr = []
    while (i < arr1.length && j < arr2.length) {
        if (arr1[i] < arr2[j]) {
            mergeArr.push(arr1[i++])
        } else {
            mergeArr.push(arr2[j++])
        }
    }
    while (i < arr1.length) {
        mergeArr.push(arr1[i++])
    }
    while (j < arr2.length) {
        mergeArr.push(arr2[j++])
    }
    return mergeArr
}

// 重写Array.filter()

Array.prototype.myFilter = function (callback) {
    const arr = this
    const result = []
    for (let i = 0; i < arr.length; i++) {
        if (callback(this[i], i, this)) {
            result.push(this[i])
        }
    }
    return result
}

// 每隔3位加逗号

function joinSymbol(num, symbol = ',') {
    const stringNum = String(num)
    let result = '', count = 0
    for (let i = stringNum.length - 1; i >= 0; i--) {
        count++
        if (count % 3 == 0 && i !== 0) {
            result = `${symbol}${stringNum[i]}${result}`
        } else {
            result = `${stringNum[i]}${result}`
        }
    }
    return result
}

// 数组扁平化

function myFlat(arr) {
    let result = []
    for (const item of arr) {
        if (Array.isArray(item)) {
            if (item.length) result = result.concat(myFlat(item))
        } else {
            result.push(item)
        }
    }
    return result
}
function myFlat2(arr) {
    return arr.reduce((acc, cur) => acc.concat((Array.isArray(cur) ? myFlat2(cur) : cur), []))
}
function myFlat3(arr) {
    return arr.flat(Infinity)
}

快速排序:

function quickSort(arr) {
    if (arr.length <= 1) return arr;

    const pivot = arr[arr.length - 1];
    const left = [];
    const right = [];

    for (let i = 0; i < arr.length - 1; i++) {
        if (arr[i] < pivot) {
            left.push(arr[i]);
        } else {
            right.push(arr[i]);
        }
    }

    return [...quickSort(left), pivot, ...quickSort(right)];
}

冒泡排序:

function bubbleSort(arr) {
    for (let i = 0; i < arr.length - 1; i++) {
        for (let j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
            }
        }
    }
    return arr;
}

归并排序:

function merge(left, right) {
    let result = [], i = 0, j = 0;

    while (i < left.length && j < right.length) {
        result.push(left[i] < right[j] ? left[i++] : right[j++]);
    }

    return result.concat(i < left.length ? left.slice(i) : right.slice(j));
}

function mergeSort(arr) {
    if (arr.length <= 1) return arr;

    const mid = Math.floor(arr.length / 2);
    return merge(mergeSort(arr.slice(0, mid)), mergeSort(arr.slice(mid)));
}

深比较对象是否相等

function isEqual(obj1, obj2) {
    // 如果两个对象不是对象类型(如基本数据类型),直接比较值
    if (typeof obj1 !== 'object' || obj1 === null || typeof obj2 !== 'object' || obj2 === null) {
        return obj1 === obj2;
    }

    // 获取对象的键集合
    const keys1 = Object.keys(obj1);
    const keys2 = Object.keys(obj2);

    // 键的数量不同,对象不等
    if (keys1.length !== keys2.length) {
        return false;
    }

    // 遍历键
    for (const key of keys1) {
        // 如果对应键的值不相等,对象不等
        if (!isEqual(obj1[key], obj2[key])) {
            return false;
        }
    }

    // 所有键对应的值都相等,对象相等
    return true;
}