前端面试题详解整理5|事件循环 哪些JS中的继承机制,函数柯里化 ,一下你们团队的 gitflow ,

70 阅读9分钟

字节前端日常实习一面

#字节跳动#
一直问项目经历,让我从自我介绍开始
• 介绍一下你们团队的 gitflow
GitFlow 是一种流行的 Git 分支管理模型,旨在帮助团队更有效地管理项目代码的开发和发布过程。以下是 GitFlow 的主要特点和流程:

  1. 主要分支

    • master 分支:代表生产环境中的稳定代码,每次提交到 master 分支的代码都应该是经过测试和验证的可发布版本。
    • develop 分支:代表当前开发的主要分支,包含了最新的开发代码,用于进行日常开发和集成测试。
  2. 辅助分支

    • feature 分支:用于开发新功能,每个功能都应该在独立的 feature 分支中开发,开发完成后再合并到 develop 分支。
    • release 分支:用于准备发布新版本,从 develop 分支拉取,并在此分支上进行发布前的测试和准备工作。测试完成后,将 release 分支合并到 master 分支发布新版本,并将代码合并回 develop 分支。
    • hotfix 分支:用于修复生产环境中的紧急 bug,从 master 分支拉取,并在此分支上进行修复。修复完成后,将 hotfix 分支合并到 master 分支发布修复版本,并将代码合并回 develop 分支。
  3. 合并策略

    • feature 分支合并到 develop 分支。
    • release 分支合并到 master 分支,并将 master 分支的变更合并回 develop 分支。
    • hotfix 分支合并到 master 分支,并将 master 分支的变更合并回 develop 分支。
  4. 版本发布

    • 每次发布新版本时,都应该创建一个新的 release 分支,并在该分支上进行版本准备和测试。
    • 发布完成后,将 release 分支合并到 master 分支,并打上标签(tag)以标记发布的版本。

GitFlow 提供了清晰的分支管理策略和版本发布流程,有助于团队更好地组织和管理项目的开发过程。然而,需要根据项目的实际情况和团队的需求进行调整和定制,以确保适合团队的工作流程。

• 鉴权怎么做得?
鉴权(Authentication)是确保用户或者系统具有访问特定资源或执行特定操作的权限的过程。在 Web 应用程序中,通常采用以下几种方式进行鉴权:

  1. 基于角色的访问控制(Role-Based Access Control,RBAC):RBAC 是一种常见的鉴权方式,它通过将用户分配到不同的角色,然后将角色授予不同的权限来管理资源访问。用户通过身份认证后,系统会根据用户所属的角色来确定其能够访问的资源和执行的操作。

  2. 基于声明的访问控制(Claims-Based Access Control):基于声明的访问控制是一种将用户的身份和权限信息存储在声明中的鉴权方式。用户在登录时会获得一个包含其身份和权限信息的令牌(Token),系统会根据令牌中的声明来决定用户是否有权访问资源。

  3. 访问令牌(Access Token):访问令牌是一种用于验证用户身份和授权访问资源的凭证。用户在登录成功后会获得一个访问令牌,然后在每次请求需要鉴权的资源时,将令牌附加在请求头中发送给服务器进行验证。

  4. 单点登录(Single Sign-On,SSO):SSO 是一种允许用户在多个应用程序或系统中使用相同的身份认证信息登录的机制。用户只需登录一次,就可以在多个系统中访问受保护的资源。

  5. OAuth2.0:OAuth2.0 是一种授权框架,用于授权第三方应用程序访问受保护的资源,而不需要用户提供其凭证。OAuth2.0 定义了多种授权方式,如授权码模式、密码模式、客户端凭证模式等。

在实际应用中,通常会结合以上多种方式进行鉴权,以满足不同场景下的需求和安全要求。例如,可以使用基于角色的访问控制管理系统内部资源的访问,而使用 OAuth2.0 等机制控制第三方应用程序对系统资源的访问。同时,为了保证安全性,还需要考虑实施适当的安全措施,如 HTTPS 协议、加密算法等。

• 项目里为什么用 echarts 和 xls.js
• 问到了一些业务组件的封装细节。
• 介绍事件循环
事件循环是 JavaScript 中处理异步操作的机制。它是一种执行模型,用于处理任务的排队和执行。事件循环允许 JavaScript 运行时环境在执行同步任务的同时,处理异步任务,以保持程序的响应性和效率。

事件循环的基本原理是不断地从任务队列中取出任务并执行,直到队列为空。它包含了以下几个主要组件:

  1. 调用栈(Call Stack):用于存储正在执行的同步任务的栈结构。当调用一个函数时,会将该函数添加到调用栈中,并在执行完成后从栈顶移除。

  2. 任务队列(Task Queue):用于存储待执行的异步任务,每个任务都与一个事件相关联。任务队列中的任务会在调用栈为空时被执行。

  3. 事件循环(Event Loop):是一个持续运行的循环,负责监听调用栈和任务队列的状态,并在合适的时机将任务移动到调用栈中执行。事件循环不断地检查调用栈是否为空,如果为空则从任务队列中取出任务并添加到调用栈中执行,直到队列为空。

  4. 微任务队列(Microtask Queue):用于存储微任务,微任务会在主任务执行完毕后立即执行。微任务队列的优先级高于宏任务队列,即微任务会在下一个事件循环迭代开始前执行完毕。

事件循环的运行过程可以总结为以下几个步骤:

  1. 执行同步任务,将函数调用添加到调用栈中执行。
  2. 当调用栈为空时,从微任务队列中取出微任务并执行,直到微任务队列为空。
  3. 如果存在宏任务,则从宏任务队列中取出一个任务,并将其添加到调用栈中执行。
  4. 重复上述步骤,直到调用栈和任务队列都为空。

总之,事件循环使得 JavaScript 可以处理异步操作,同时保持程序的响应性和效率。通过合理地安排和处理异步任务,可以避免阻塞主线程,提高程序的性能和用户体验。

• 介绍一下 class 的继承机制
• 还知道哪些JS中的继承机制?
在 JavaScript 中,类的继承机制是通过原型链来实现的。当一个类继承另一个类时,它实际上是继承了父类的原型对象。这意味着子类可以访问父类原型对象上的属性和方法。下面是一个简单的示例:

// 定义一个父类
class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

// 定义一个子类,继承自父类 Animal
class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }

  speak() {
    console.log(`${this.name} barks.`);
  }
}

// 创建一个 Dog 实例
const myDog = new Dog('Buddy', 'Golden Retriever');
myDog.speak(); // 输出:Buddy barks.

在上面的示例中,Dog 类继承了 Animal 类。在子类 Dog 中使用 extends 关键字指定了父类 Animal,并使用 super 关键字在子类的构造函数中调用父类的构造函数。这样就实现了子类对父类的继承。

除了使用类和原型链实现继承外,JavaScript 中还有其他一些实现继承的机制,包括:

  1. 原型继承:通过将一个对象作为另一个对象的原型来实现继承。可以使用 Object.create() 方法或者直接设置 __proto__ 属性来创建具有指定原型的新对象。

  2. 构造函数继承:通过在子类构造函数中调用父类构造函数来实现继承。这种方式实现的继承不涉及原型链,而是通过在子类实例中创建父类属性的副本来实现的。

  3. 组合继承:通过结合原型链继承和构造函数继承来实现继承。即在子类的构造函数中调用父类的构造函数,同时将子类的原型设置为一个新创建的父类实例。

  4. 寄生组合继承:是组合继承的一种改进版本,它避免了调用两次父类构造函数,提高了性能。它的实现方式是将子类的原型设置为一个父类的实例,然后通过调整子类的构造函数,使得在创建子类实例时不会调用父类的构造函数。

• 读代码,也是事件循环相关的代码,密密麻麻一个屏幕半,写出来打印的先后顺序,基本上考察promise 和 async
• 写代码实现函数柯里化
函数柯里化是一种将接受多个参数的函数转换为接受单个参数的函数链式调用的技术。下面是一个简单的 JavaScript 示例实现函数柯里化:

function curry(func) {
  return function curried(...args) {
    if (args.length >= func.length) {
      return func(...args);
    } else {
      return function(...nextArgs) {
        return curried(...args, ...nextArgs);
      };
    }
  };
}

// 示例函数
function add(a, b, c) {
  return a + b + c;
}

// 使用柯里化
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3)); // 输出:6
console.log(curriedAdd(1, 2)(3)); // 输出:6
console.log(curriedAdd(1)(2, 3)); // 输出:6
console.log(curriedAdd(1, 2, 3)); // 输出:6

在上面的示例中,curry 函数接受一个函数作为参数,并返回一个新的柯里化函数。这个柯里化函数可以接受多个参数,并在参数数量足够时执行原始函数,否则返回一个新的函数,继续接受剩余的参数。通过嵌套调用函数,实现了函数柯里化的效果。

• 有什么问题要问我?

作者:宇宙机吴彦祖
链接:www.nowcoder.com/feed/main/d…
来源:牛客网