记录

69 阅读4分钟

1. es6,es7相关新增属性

-  箭头函数
-  解构赋值
-  模板字面量
-  块级作用域变量
-  Promise
-  -----es7------
-  类
-  包含操作符(Includes)
-  Object.values()

3. css定位

-  position    

4. 如何调用原生api的同时打印log

-  函数劫持
```js
// 保存原生的 push() 方法到临时变量
const originalPush = Array.prototype.push;

// 重新定义 push() 方法并添加日志打印逻辑
Array.prototype.push = function(...items) {
  console.log('Calling push() with:', items);

  // 调用原生的 push() 方法
  originalPush.apply(this, items);

  console.log('push() called. New length:', this.length);
};

// 使用原生的 push() 方法,但会打印日志
const arr = [1, 2, 3];
arr.push(4, 5);
```

5. 链式调用

-   同一个对象上连续调用多个方法,而无需每次都引用该对象。在链式调用中,每个方法都会返回对象本身,从而使得可以在返回的对象上继续调用其他方法。

-   ```js
    const person = {
      name: '',
      age: 0,
      setName(name) {
        this.name = name;
        return this; // 返回对象本身,用于链式调用
      },
      setAge(age) {
        this.age = age;
        return this; // 返回对象本身,用于链式调用
      },
      introduce() {
        console.log(`My name is ${this.name} and I'm ${this.age} years old.`);
        return this; // 返回对象本身,用于链式调用
      }
    };

    // 链式调用示例
    person.setName('John').setAge(25).introduce();
    ```

7. BFC

-   BFC 是一个独立的渲染区域。每个 BFC 都是独立垂直流动的,并且内部块级元素在垂直方向上一个接一个地放置。
  • 触发 BFC 的条件包括:
    • 根元素(html)
    • float 属性不为 none
    • position 属性为 absolute 或 fixed
    • display 属性为 inline-blocktable-celltable-captionflexgridinline-flex 或 inline-grid
    • overflow 属性不为 visible

9. 实现一个trim方法,删除字符串开头与结尾空白

```js
    const trim = (data) =>{
         return  data.replace(/^\s+|\s+$/g,'')
    }
```

9. promise底层,为了解决什么问题,不用promise能用什么

10. 实现promise.allsettled

function promiseAllSettled(promises) {
  const settledPromises = [];
  const promisesCount = promises.length;
  let settledCount = 0;
  return new Promise((resolve) => {
    promises.forEach((promise, index) => {
      Promise.resolve(promise)
        .then((value) => {
          settledPromises[index] = { status: "fulfilled", value };
          settledCount++;
          if (settledCount === promisesCount) {
            resolve(settledPromises);
          }
        })
        .catch((reason) => {
          settledPromises[index] = { status: "rejected", reason };
          settledCount++;
          if (settledCount === promisesCount) {
            resolve(settledPromises);
          }
        });
    });
  });
}
// 示例用法
const promises = [
  Promise.resolve("Resolved Promise 1"),
  Promise.reject("Rejected Promise 1"),
  Promise.resolve("Resolved Promise 2"),
];
promiseAllSettled(promises).then((results) => {
  results.forEach((result) => {
    if (result.status === "fulfilled") {
      console.log(`Fulfilled: ${result.value}`);
    } else {
      console.log(`Rejected: ${result.reason}`);
    }
  });
});

11. 判断逻辑里能否调用hooks

不能,因为是列表实现,写的话可能会造成数据混乱

12. 什么是列表实现

从上到下

13. .next(迭代器)、

1.使用yield 2.返回next 函数

14. 设计模式

  1. 单例模式(Singleton Pattern):确保某个类只有一个实例,并提供全局访问点。
  2. 链式调用模式(Chain of Responsibility Pattern):通过一条链来组织多个对象并使这些对象能够依次处理请求。
  3. 工厂模式(Factory Pattern):用于创建对象的通用接口,根据参数的不同返回不同类的实例。
  4. 观察者模式(Observer Pattern):定义了对象间的一种一对多的依赖关系,当一个对象状态改变时,所有相依它的对象都会得到通知并被自动更新。
  5. 原型模式(Prototype Pattern):用于创建新对象的方法,可以基于现有的对象创建对象,而无需重新创建一个新的类。
  6. 工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定实例化哪个类。
  7. 适配器模式(Adapter Pattern):使得原本接口不兼容的类可以一起工作,通过包装一个对象,将其转换成所需接口。
  8. 策略模式(Strategy Pattern):定义了一系列的算法,将每个算法封装起来,并让它们可以相互替换。
  9. 装饰器模式(Decorator Pattern):动态地给一个对象添加一些额外的职责,就增加功能而言,它比生成子类方式更为灵活。

15. 执行顺序

let p = [];
setTimeout(() => {
  console.log("timeout 0");
}, 0);
(function () {
  let i = 0;
  for (; i < 3; i++) {
    p[i] = function () {
      return new Promise(function (resolve) {
        console.log(`promise111 ${i} `);
        resolve(`promise222 ${i * i}`);
      });
    };
  }
})();
async function b() {
  console.log("async111 -1");
}
function a() {
  console.log(`async222 ${p.length}`);
  return async function () {
    console.log(`async333 ${p.length}`);
    await b();
    console.log("async444 -2");
  };
}
p.push(a());
p[1]().then(console.log);
p[3]();

img_v2_041ce47c-1412-437e-8c6a-adf8fd87d3cg.jpg

16. merge

function mergeArrays(arr1, arr2) {
  const mergedArray = [...arr1, ...arr2];
  const result = [];
  mergedArray.forEach((num) => {
    if (!result.includes(num)) {
      const count1 = arr1.filter((x) => x === num).length;
      const count2 = arr2.filter((x) => x === num).length;
      for (let i = 0; i < Math.max(count1, count2); i++) {
        result.push(num);
      }
    }
  });
  return result;
}
const arr1 = [1, 2, 100, 5, 5];
const arr2 = [2, 2, 2, 5, 5, 100];
const result = mergeArrays(arr1, arr2);

16. 手写instanceOf

image.png

17. 通过 GitHub REST API 在指定仓库中添加一个 issue,可以按照以下步骤进行:

  1. 获取访问令牌:首先,您需要获取一个具有足够权限的访问令牌(access token),用于进行 API 请求。您可以在 GitHub 上创建一个个人访问令牌,确保该令牌具有足够的权限来创建 issue。

  2. 构建 API 请求:使用任意的 HTTP 客户端(如 Postman 或 cURL),构建一个 POST 请求到指定仓库的 issue API 端点。API 端点的 URL 通常类似于 https://api.github.com/repos/OWNER/REPO/issues,其中 "OWNER" 是仓库所有者的用户名或组织名,"REPO" 是仓库名称。

  3. 设置请求头部:在请求中添加必要的头部信息。最重要的是在头部中添加 "Authorization" 字段,并将值设置为 "Bearer YOUR_ACCESS_TOKEN",其中 "YOUR_ACCESS_TOKEN" 是您在第一步中获取的访问令牌。

  4. 提供请求正文:在请求正文(body)中提供需要创建的 issue 的详细信息。通常,issue 的标题可以通过设定 JSON 对象中的 "title" 字段来提供,例如:{"title": "New Issue"}。您还可以提供其他可选字段,如描述("body" 字段)和标签("labels" 字段)。

  5. 发送请求:将构建好的请求发送到 GitHub REST API。

  6. 检查响应:检查 API 响应以确认是否成功创建了 issue。成功创建的话,API 将返回新创建的 issue 的详细信息,包括其编号、标题、描述等。

18.要使用个人账号授权码在 Postman 中实现拉取指定仓库的 issue 列表,您可以按照以下步骤进行操作:

  1. 创建个人访问令牌(Personal Access Token):

    • 登录您的 GitHub 账号,并进入 "Settings"(设置)页面。
    • 在左侧导航栏中,选择 "Developer settings"(开发者设置)。
    • 在 "Personal access tokens"(个人访问令牌)部分,点击 "Generate new token"(生成新令牌)。
    • 提供一个描述,勾选适当的权限(至少需要 repo 权限来访问仓库的 issue),然后点击 "Generate token"(生成令牌)。
    • 复制生成的个人访问令牌,这将用作后续请求的身份验证凭据。
  2. 配置 Postman 请求:

    • 打开 Postman 应用程序,并创建一个新的请求。
    • 在请求的 Headers 部分,添加一个名为 "Authorization" 的 Header,值为 "Bearer YOUR_ACCESS_TOKEN",将 "YOUR_ACCESS_TOKEN" 替换为您在第一步中生成的个人访问令牌。
    • 设置请求的 URL 为 GitHub REST API 的相关端点,用于获取指定仓库的 issue 列表。例如,GET 请求的 URL 可能类似于:https://api.github.com/repos/OWNER/REPO/issues,将 "OWNER" 替换为仓库所有者的用户名或组织名,将 "REPO" 替换为仓库的名称。
    • 发送请求并等待响应。

19 OAuth 2.0 认证协议的实现原理

OAuth 2.0 是一种常用的开放授权协议,用于授权第三方应用程序访问受保护的资源,而无需共享用户凭据。下面是 OAuth 2.0 认证协议的实现原理:

  1. 客户端注册:第三方应用程序(客户端)需要在授权服务器上注册,并获得客户端标识和客户端密钥,以便与授权服务器进行通信。

  2. 用户授权请求:客户端向用户发起授权请求,将用户重定向到授权服务器。授权请求包括客户端标识、请求的范围(要访问的资源)、重定向URI(用于在授权后将用户重定向回客户端)等信息。

  3. 用户授权:用户在授权服务器上登录,并被要求授权客户端访问特定资源。用户可以确认或拒绝授权请求。

  4. 授权许可颁发:如果用户授权客户端访问资源,授权服务器将颁发一个授权许可(authorization grant)给客户端。授权许可的类型可以是授权码(authorization code)、隐式授权许可(implicit grant)、密码授权许可(password grant)或客户端凭证授权许可(client credentials grant)。

  5. 认证许可交换:客户端使用授权许可与授权服务器进行交互,以获取访问令牌(access token)。访问令牌是客户端用于访问受保护资源的凭据。

  6. 访问资源:客户端使用访问令牌向资源服务器发送请求,以获取受保护的资源。资源服务器会验证访问令牌的有效性,并向客户端返回请求的资源。

除了 OAuth 2.0,以下是其他常见的认证协议的实现原理:

  • OpenID Connect (OIDC):OIDC 是基于 OAuth 2.0 的身份验证协议。它通过在 OAuth 2.0 的基础上添加身份验证流程来提供身份验证和用户信息的获取。OIDC 在用户授权成功后,通过 ID 令牌和访问令牌返回用户的身份信息给客户端。

  • CAS(Central Authentication Service):CAS 是一种单点登录协议,用于验证用户身份并提供对受保护资源的访问。CAS 使用票据(ticket)来进行身份验证,客户端在验证成功后会获得一个票据。客户端使用票据向 CAS 服务器请求访问令牌,然后使用访问令牌访问资源。

  • Basic Auth(基本身份验证):Basic Auth 是一种简单的身份验证协议,客户端将用户名和密码编码为 Base64 字符串,并在请求的 Authorization 头中发送给服务器。服务器通过解码该字符串并验证用户名和密码来进行身份验证。

  • API Key(应用程序密钥):API Key 是一种用于身份验证的令牌,通常由服务提供商生成并提供给客户端应用程序。客户端在每个请求中将 API Key 包含在头部或查询参数中,服务器验证 API Key 的有效性来进行身份验证。

执行顺序

async function async1() {
  console.log('async1 start')
  await async2()
  console.log('async1 end')
}
async function async2() {
  console.log('async2')
}
console.log('begin')
setTimeout(function () {
    console.log('setTimeout 0');
});
async1();
new Promise(function (resolve) {
    console.log('promise1');
    for (let i = 0; i < 1000; i++) {
        i === 99 && resolve();
    }
    console.log('promise2');
}).then(function () {
    console.log('then1');
    setTimeout(() => {
        console.log('setTimeout2 between promise1&2')
    })
}).then(() => {
    console.log('promise 3')
});
console.log('end')

begin
 async1 start
async2
 promise1
 promise2
 end
 async1 end
 then1
 promise 3
 setTimeout 0
 setTimeout2 between promise1&2

状态码

  • 1xx(信息性状态码):表示接收的请求正在处理或需要进一步处理。

    • 100 Continue:服务器已接收到请求的初始部分,客户端应继续发送剩余的请求。
    • 101 Switching Protocols:服务器已经理解并接受了客户端请求,在切换协议之前需要执行一些操作。
  • 2xx(成功状态码):表示请求已成功被服务器接收、理解和处理。

    • 200 OK:请求成功,服务器返回了请求的数据。
    • 201 Created:请求成功,并在服务器上创建了新的资源。
    • 204 No Content:请求成功,但服务器没有返回任何内容。
  • 3xx(重定向状态码):表示客户端需要执行附加操作以完成请求。

    • 301 Moved Permanently:请求的资源已永久移动到新的 URL。
    • 302 Found:请求的资源暂时移动到新的 URL。
    • 304 Not Modified:客户端可以使用缓存的版本,因为请求的资源未被修改。协商缓存的响应状态码
  • 4xx(客户端错误状态码):表示客户端发送的请求有错误。

    • 400 Bad Request:请求无效,服务器无法理解该请求。
    • 401 Unauthorized:请求需要用户身份验证。
    • 403 Forbidden" 表示服务器拒绝了请求,即使进行身份验证也无法获得访问权限。
    • 404 Not Found:请求的资源不存在。
  • 5xx(服务器错误状态码):表示服务器在处理请求时发生错误。

    • 500 Internal Server Error:服务器遇到了意外的错误,无法完成请求。
    • 502 Bad Gateway" 响应时,这通常表示客户端无法访问所需的资源,因为代理或网关服务器无法与上游服务器进行有效通信
    • 503 Service Unavailable:服务器暂时不可用,通常由于过载或维护。
  • 403 Forbidden" 与 "401 Unauthorized" 不同。"401 Unauthorized" 表示请求需要进行身份验证,而 "403 Forbidden" 表示服务器拒绝了请求,即使进行身份验证也无法获得访问权限。

版本比较

const compareVersions = () => {
  const version1Parts = version1.split('.').map(Number);
  const version2Parts = version2.split('.').map(Number);

  for (let i = 0; i < Math.max(version1Parts.length, version2Parts.length); i++) {
    const part1 = version1Parts[i] || 0;
    const part2 = version2Parts[i] || 0;

    if (part1 < part2) {
      return `${version1} is less than ${version2}`;
    } else if (part1 > part2) {
      return `${version1} is greater than ${version2}`;
    }
  }

  return `${version1} is equal to ${version2}`;
};

强缓存

常用的控制强缓存的 HTTP 响应头字段有两个:

  1. Cache-Control:它是一个通用的缓存控制字段,用于指定资源的缓存策略。常见的指令包括:

    • public:资源可以被任何缓存(包括客户端和中间代理服务器)缓存。
    • private:资源只能被客户端缓存,不允许中间代理服务器缓存。
    • max-age=<seconds>:设置资源的最大缓存时间,以秒为单位。
    • no-cache:强制客户端在使用缓存之前先与服务器确认资源是否被修改。
    • no-store:禁止缓存,每次请求都要向服务器重新获取资源。
  2. Expires:它指定了资源的过期时间,是一个具体的日期/时间。如果当前时间在 Expires 指定的时间之前,资源被认为是有效的,浏览器将直接从缓存加载资源。

cookie 过期时间

  1. Expires 属性:通过设置 Expires 属性,可以指定一个具体的过期日期和时间
  2. Max-Age 属性:通过设置 Max-Age 属性,可以指定 Cookie 的有效期(以秒为单位)。
  3. Domain(域名):指定哪些域名可以访问该 Cookie。默认情况下,Cookie 仅适用于设置它的域名。可以使用 Domain 属性来扩展其适用范围,例如设置为 ".example.com",使得该 Cookie 在 example.com 及其子域名下都可用。
  4. Path(路径):指定哪些路径可以访问该 Cookie。默认情况下,Cookie 仅适用于设置它的路径。可以使用 Path 属性来限制其适用范围,例如设置为 "/app",使得该 Cookie 仅在以 "/app" 开头的路径下可用。
  5. Secure(安全性):如果设置了 Secure 属性,并且用户正在通过 HTTPS 连接访问网站时,浏览器只会在加密的安全连接中发送该 Cookie。这有助于保护敏感信息的安全性。
  6. HttpOnly:如果设置了 HttpOnly 属性,JavaScript 将无法访问该 Cookie。这有助于防止跨站点脚本攻击(XSS 攻击),因为攻击者无法通过 JavaScript 访问包含敏感信息的 Cookie。
  7. Cookie 的跨域使用受到同源策略的限制。同源策略要求网页中的脚本只能访问与其所在域名、协议和端口相同的资源,因此默认情况下,一个域名下的 Cookie 不能被其他域名使用。
  • 然而,可以通过设置 Cookie 的 "Domain" 属性来允许其他域名访问该 Cookie。使用合适的 "Domain" 值,可以允许 Cookie 在指定域名及其子域名下被共享。例如,设置 "Domain" 为 ".example.com",则该 Cookie 可以在 example.com 及其所有子域名(如 subdomain.example.com)下被访问和使用。

  • 设置 "SameSite=None" 属性允许跨站点共享 Cookie,即允许在不同域名之间共享 Cookie。"SameSite=None" 用于解除同源策略对 Cookie 的限制,以便在跨域场景下使用。

flex 布局

  • flex: 0 1 auto 放大,缩小,自己
  • flex:1。---》 flex 1 1 auto
  • flex:0 ---》 flex 0 0 auto
  • flex: none 不生效flex 等同于 flex 0 0 auto

json数字加1

function checkNumAdd(parm) {
  const cloneParm = JSON.parse(JSON.stringify(parm));
  if (typeof cloneParm === 'number') {
    return cloneParm + 1;
  } else if (typeof cloneParm === 'object') {
    const res = {};
    for (const key in cloneParm) {
      res[key] = checkNumAdd(cloneParm[key]);
    }
    return res;
  } else if (Array.isArray(cloneParm)) {
    return cloneParm.map(checkNumAdd);
  } else {
    return cloneParm
  }
}