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属性不为noneposition属性为absolute或fixeddisplay属性为inline-block、table-cell、table-caption、flex、grid、inline-flex或inline-gridoverflow属性不为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. 设计模式
- 单例模式(Singleton Pattern):确保某个类只有一个实例,并提供全局访问点。
- 链式调用模式(Chain of Responsibility Pattern):通过一条链来组织多个对象并使这些对象能够依次处理请求。
- 工厂模式(Factory Pattern):用于创建对象的通用接口,根据参数的不同返回不同类的实例。
- 观察者模式(Observer Pattern):定义了对象间的一种一对多的依赖关系,当一个对象状态改变时,所有相依它的对象都会得到通知并被自动更新。
- 原型模式(Prototype Pattern):用于创建新对象的方法,可以基于现有的对象创建对象,而无需重新创建一个新的类。
- 工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定实例化哪个类。
- 适配器模式(Adapter Pattern):使得原本接口不兼容的类可以一起工作,通过包装一个对象,将其转换成所需接口。
- 策略模式(Strategy Pattern):定义了一系列的算法,将每个算法封装起来,并让它们可以相互替换。
- 装饰器模式(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]();
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
17. 通过 GitHub REST API 在指定仓库中添加一个 issue,可以按照以下步骤进行:
-
获取访问令牌:首先,您需要获取一个具有足够权限的访问令牌(access token),用于进行 API 请求。您可以在 GitHub 上创建一个个人访问令牌,确保该令牌具有足够的权限来创建 issue。
-
构建 API 请求:使用任意的 HTTP 客户端(如 Postman 或 cURL),构建一个 POST 请求到指定仓库的 issue API 端点。API 端点的 URL 通常类似于
https://api.github.com/repos/OWNER/REPO/issues,其中 "OWNER" 是仓库所有者的用户名或组织名,"REPO" 是仓库名称。 -
设置请求头部:在请求中添加必要的头部信息。最重要的是在头部中添加 "Authorization" 字段,并将值设置为 "Bearer YOUR_ACCESS_TOKEN",其中 "YOUR_ACCESS_TOKEN" 是您在第一步中获取的访问令牌。
-
提供请求正文:在请求正文(body)中提供需要创建的 issue 的详细信息。通常,issue 的标题可以通过设定 JSON 对象中的 "title" 字段来提供,例如:
{"title": "New Issue"}。您还可以提供其他可选字段,如描述("body" 字段)和标签("labels" 字段)。 -
发送请求:将构建好的请求发送到 GitHub REST API。
-
检查响应:检查 API 响应以确认是否成功创建了 issue。成功创建的话,API 将返回新创建的 issue 的详细信息,包括其编号、标题、描述等。
18.要使用个人账号授权码在 Postman 中实现拉取指定仓库的 issue 列表,您可以按照以下步骤进行操作:
-
创建个人访问令牌(Personal Access Token):
- 登录您的 GitHub 账号,并进入 "Settings"(设置)页面。
- 在左侧导航栏中,选择 "Developer settings"(开发者设置)。
- 在 "Personal access tokens"(个人访问令牌)部分,点击 "Generate new token"(生成新令牌)。
- 提供一个描述,勾选适当的权限(至少需要
repo权限来访问仓库的 issue),然后点击 "Generate token"(生成令牌)。 - 复制生成的个人访问令牌,这将用作后续请求的身份验证凭据。
-
配置 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 认证协议的实现原理:
-
客户端注册:第三方应用程序(客户端)需要在授权服务器上注册,并获得客户端标识和客户端密钥,以便与授权服务器进行通信。
-
用户授权请求:客户端向用户发起授权请求,将用户重定向到授权服务器。授权请求包括客户端标识、请求的范围(要访问的资源)、重定向URI(用于在授权后将用户重定向回客户端)等信息。
-
用户授权:用户在授权服务器上登录,并被要求授权客户端访问特定资源。用户可以确认或拒绝授权请求。
-
授权许可颁发:如果用户授权客户端访问资源,授权服务器将颁发一个授权许可(authorization grant)给客户端。授权许可的类型可以是授权码(authorization code)、隐式授权许可(implicit grant)、密码授权许可(password grant)或客户端凭证授权许可(client credentials grant)。
-
认证许可交换:客户端使用授权许可与授权服务器进行交互,以获取访问令牌(access token)。访问令牌是客户端用于访问受保护资源的凭据。
-
访问资源:客户端使用访问令牌向资源服务器发送请求,以获取受保护的资源。资源服务器会验证访问令牌的有效性,并向客户端返回请求的资源。
除了 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 响应头字段有两个:
-
Cache-Control:它是一个通用的缓存控制字段,用于指定资源的缓存策略。常见的指令包括:
public:资源可以被任何缓存(包括客户端和中间代理服务器)缓存。private:资源只能被客户端缓存,不允许中间代理服务器缓存。max-age=<seconds>:设置资源的最大缓存时间,以秒为单位。no-cache:强制客户端在使用缓存之前先与服务器确认资源是否被修改。no-store:禁止缓存,每次请求都要向服务器重新获取资源。
-
Expires:它指定了资源的过期时间,是一个具体的日期/时间。如果当前时间在 Expires 指定的时间之前,资源被认为是有效的,浏览器将直接从缓存加载资源。
cookie 过期时间
- Expires 属性:通过设置 Expires 属性,可以指定一个具体的过期日期和时间
- Max-Age 属性:通过设置 Max-Age 属性,可以指定 Cookie 的有效期(以秒为单位)。
- Domain(域名):指定哪些域名可以访问该 Cookie。默认情况下,Cookie 仅适用于设置它的域名。可以使用 Domain 属性来扩展其适用范围,例如设置为 ".example.com",使得该 Cookie 在 example.com 及其子域名下都可用。
- Path(路径):指定哪些路径可以访问该 Cookie。默认情况下,Cookie 仅适用于设置它的路径。可以使用 Path 属性来限制其适用范围,例如设置为 "/app",使得该 Cookie 仅在以 "/app" 开头的路径下可用。
- Secure(安全性):如果设置了 Secure 属性,并且用户正在通过 HTTPS 连接访问网站时,浏览器只会在加密的安全连接中发送该 Cookie。这有助于保护敏感信息的安全性。
- HttpOnly:如果设置了 HttpOnly 属性,JavaScript 将无法访问该 Cookie。这有助于防止跨站点脚本攻击(XSS 攻击),因为攻击者无法通过 JavaScript 访问包含敏感信息的 Cookie。
- 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
}
}