52前端面试问题 - JavaScript
#javascript #网络开发人员 #前端 #面试

介绍

许多初学者和经验丰富的开发人员已经开始遇到,并注意到求职问题。确实,市场竞争水平比2 - 3年前高得多。

当前现实中最好的事情是继续学习。

在本文中,我在面试中遇到的前端开发人员的“问题:答案”格式编写了52个问题。这些问题主要是针对初级的,部分朝向中层。

P.S。尽管大多数问题都是针对大三的,但通过准备这些问题并彻底研究主题,我还是能够确保作为中间前端开发人员的工作。

1. JavaScript中存在哪些数据类型?

  1. 数字 - 数字
  2. 字符串 - 字符串
  3. 布尔值 - 布尔类型,是或错误
  4. 对象 - javascript对象
  5. null-代表“无”,“空”或“未知值”的特殊值。
  6. 未定义 - “尚未分配值”。如果声明变量但没有分配的值,则分配此类型。
  7. 符号 - 可以用作对象属性的标识符的唯一且不可变的数据类型。
  8. bigint-用于创建大数字。

const bigInt = 1234567890123456789012345678901234567890n;

Learn more

2.“ ==”和“ ===”之间有什么区别?

操作员“ ==”检查抽象平等,而“ ===”检查严格的平等。
换句话说,“ ==”操作员在比较之前执行必要的类型转换,而“ ===”不执行类型转换。因此,如果两个值不是同一类型,则使用“ ===”操作员时会返回false。

Learn more

3.声明变量的方法是什么?

有4种声明变量的方法:

  foo = 123; 
  var foo = 123; 
  let a = 123; 
  const a = 123; 

使用“ var”关键字声明变量类似于第一个方法。以这种方式声明的变量具有全局或功能范围,并且缺乏块范围,这是一个劣势。
“让”和“ const”是声明变量的优选方法。它们具有块范围,这意味着在内部声明的变量,例如一个函数,在该函数之外不会可见。 “ const”变量是不可变的,但是如果它是对象,则可以更改其属性,如果它是数组,则可以修改并添加元素。

Learn more

4.零和未定义的差异是什么?

这两个选项代表一个空值。如果我们初始化一个变量但不为其分配一个值,则将为其分配一个特殊标记 - 未定义。 null是手动分配的。

null是一个特殊的值,代表“无”,“空”或“未知值”。如果我们需要清除变量的值,我们将设置foo = null。

Learn more

5.箭头功能和常规功能的差异。

  1. 箭头功能不能使用参数对象。
  2. 它们具有不同的语法。
  3. 箭头功能没有自己的上下文。引用此内容时,箭头功能从周围的范围中获取上下文。
  4. 箭头函数不能用作构造函数函数。换句话说,它们不能用新的关键字调用。

Learn more

6.什么是关闭,为什么需要它们?

闭合是一个函数,以及它可以访问的所有外部变量。例如,有一个函数具有嵌套函数,该函数将关闭并保留其父的变量。

function parent() { 
    const a = 5; 
    return function child() { 
        console.log(5); // child closes over the variable 'a'; 
    } 
}

Learn more

7.什么是模板文字?

模板文字被包装在背景中(),并允许多行字符串。他们还允许在其中嵌入表达。

const name = 'John';
const text = `User's name is ${name}`;

console.log(text) // User's name is John

Learn more

8.什么是设置和映射?

MAP是一个集合,是一种数据结构,该数据结构以键值对的原理运行,类似于对象。但是,地图和对象之间的主要区别在于地图允许使用任何类型的键。
集合是一种无键的集合,一个数组,每个值只能出现一次。 set在自身内存储独特的值。

Learn more

9.如何检查对象中的财产存在?

第一种方法是使用HasownProperty函数,该函数可用于每个对象。
第二种方法是使用在运算符中。但是,当使用IN操作员时,必须谨慎行事,因为它检查链中的所有原型。

const obj = {
  year: 2023,
  name: "John"
}

console.log(obj.hasOwnProperty("year")) // true
console.log("year" in obj) // true
console.log("ye" in obj) // false

Learn more

10.如何访问对象属性?

第一种方法是静态的,使用点表示法:obj.a。
第二种方式是动态的,使用方括号:obj ['a']。

const obj = {
  year: 2023,
  name: "John"
}

console.log(obj['year']) // 2023
console.log(obj.name) // John

Learn more

11.使用数组的主要方法是什么?

  • foreach-一种迭代方法,用于循环通过数组,不会返回任何内容。它为常规循环提供了更优雅的替代品。
  • 过滤器(回调,[args]) - 一种使用提供的功能过滤数组的方法。它创建了一个新数组,仅包含来自原始数组的元素,该元素(item,i,arr)函数返回true。
  • map(回调,[args]) - 一种转换数组的方法。它创建了一个新数组,该数组由调用阵列的每个元素调用回调(item,i,arr)函数的结果。
  • 降低(回调,[initvalue]) - 一种在维护中间结果的同时依次处理数组的每个元素的方法。

Learn more

12.创建对象的方法是什么?

使用构造函数函数:

function User(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}
const user = new User('John', 'Johnson');
console.log(user); // { firstName: 'John', lastName: 'Johnson' }

使用对象文字符号:

const user = {
  firstName: 'John',
  lastName: 'Johnson'
};

使用类:

class User {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
}
const user = new User('John', 'Johnson');
console.log(user); // { firstName: 'John', lastName: 'Johnson' }

使用创建函数:

const user = Object.create({
  firstName: 'John',
  lastName: 'Johnson'
});

13.什么是诺言?

诺言是一个旨在使用异步代码的对象。它保持自己的状态。最初,承诺处于待处理状态,然后如果成功执行异步代码,则它将过渡到实现的状态,或者如果发生错误,则将其过渡到被拒绝的状态。承诺接受两个回调功能:

  • 满足,这是在实现承诺时会触发的。
  • 重新注射,当拒绝承诺时会触发。

使用模式如下:

  1. 需要执行某些异步的代码创造了诺言并返回它。
  2. 收到承诺后,外部代码将充满和撤销的回调函数传递给了它。
  3. 完成该过程后,异步代码过渡到已满或拒绝状态的承诺,自动调用相应的回调函数。

Learn more

14.什么是异步/正在等待?如何使用它?

async/等待是一种特殊的语法,用于合作承诺。
用异步语法声明的函数始终返回承诺。
关键字等待使JavaScript解释器等到等待右侧的承诺在继续执行之前实现等待的承诺。然后,它将返回结果,并将执行代码执行。等待无法用于常规功能。

Learn more

15.如何检查对象是否为数组?

要检查对象是否是数组,您可以使用array.isarray()方法。它以对象为输入,如果对象为数组,则返回true,如果不是数组,则false。

const obj1 = { person: 'John' }
const obj2 = new Array(2)
const obj3 = []

console.log(Array.isArray(obj1)) // false
console.log(Array.isArray(obj2)) // true
console.log(Array.isArray(obj3)) // true

16.传播操作员的目的是什么?

传播操作员(...)用于解开数组或对象。
它允许您扩展具有峰值的元素,例如阵列和字符串。

  • 它用于呼叫的预期参数次数为零或更多的函数。
  • 它用于阵列文字或表达式中。
  • 它用于对象文字,其中键值对的数量应为零或更多。
const date = [2000, 3, 7] 
const newArray = [...date] // [2000, 3, 7]

Learn more

17.复制对象时如何避免参考依赖性?

如果对象不包含嵌套对象,例如:

const obj = {
 firstName: 'John',
 lastName: 'Johnson'
}

在这种情况下,您可以使用传播操作员 object.assign()方法:

const copy = {...obj}
// or
const copy = Object.assign({}, obj)

如果对象包含嵌套对象:

const obj = {
    data: {
        id: 1
    }
}

在这种情况下,您需要执行深层副本。
慢> 是:

const copy = JSON.parse(JSON.stringify(obj))

此方法适用于没有原型和功能的对象。
另外,您可以使用lodash库的 deepclone()函数。

18.如何更改函数的上下文?

  1. 使用 bind()方法,该方法返回具有界面上下文的新功能。
function foo() {
    return this
}
const obj = { name: 'John' }
const newFoo = foo.bind(obj)
console.log(newFoo()) // { name: 'John' }
  1. 使用 call() apply()方法。主要区别在于 call()接受一系列参数,而 apply()接受一系列参数作为第二个参数。
function foo() {
    return this
}

const obj = { name: 'John' }
foo.call(obj, 'arg1', 'arg2') // { name: 'John' }
foo.apply(obj, ['arg1', 'arg2']) // { name: 'John' }

19.什么是三元操作员?

三元操作员是IF-ELSE语句的速记符号。操作员以问号和结肠代表。它被称为三元,因为它是唯一需要三个参数的操作员。

条件?表达式_1:expression_2

num >= 10 ? 'more than 10' : 'less than 10'
// is equal to
if (num >= 10) {
    return 'more than or equal to 10'
}
return 'less than 10'

Learn more

20.什么是破坏性?

破坏性是一种语法,它允许我们将数组和对象拆除到多个变量中。

const arr = ['John', 'Johnson']
const [firstName, lastName] = arr
console.log(firstName, lastName) // John Johnson

OR

const obj = {
    firstName: 'John',
    lastName: 'Johnson'
}
const { firstName, lastName } = obj;
console.log(firstName, lastName) // John Johnson

Learn more

21.什么是DOM?

DOM代表文档对象模型。它是HTML文档作为标签树的表示。
示例
DOM树中的每个节点都是对象。

JS DOM

HTML文档的基本元素是标签。
根据文档对象模型(DOM),每个HTML标签都是对象。嵌套标签是其父元素的“孩子”。标签中的文字也是对象。所有这些对象都可以使用JavaScript访问,我们可以使用它们来操纵页面。

Learn more

22.活动循环是什么?

事件循环 - 管理代码执行的机制。它以正确的顺序处理事件处理和任务执行。事件循环的主要思想是JavaScript在单线程环境中运行,但可以处理异步操作。当诸如服务器请求之类的异步操作完成时,它将相应的事件放入事件队列中。事件循环在循环中起作用,以它们到达的顺序处理这些事件。它需要从队列中进行事件,并将其传递给执行。如果事件包含回调或处理程序,则将调用,并执行与该事件关联的代码。事件循环还处理其他任务,例如计时器和微型任务(承诺)。它管理所有这些任务的执行顺序,以确保一致性并阻止代码执行的主线程。

简而言之,JavaScript中的事件循环通过处理队列中的事件并按照正确的顺序执行相应的代码来管理异步操作。这允许JavaScript在使用异步操作时有效地响应并有效地利用其资源。

Event loop

我强烈建议您在提供的链接上观看视频,因为该主题很重要,值得一篇单独的文章。

Learn more

23.什么是原型继承?

JavaScript中的每个对象都有一个属性 - 原型。方法和属性可以添加到原型中。可以根据原型创建其他对象。创建的对象自动继承其原型的方法和属性。如果对象中没有属性,则将在原型中执行其搜索。
Learn more

24.可选的链接操作员是什么?

可选的链式操作员?停止评估并返回未定义的零件?是未定义的或空的。

让我们考虑一个用户对象。大多数用户都有一个地址用户。address,with street user. address.street,但是有些用户尚未提供地址。在这种情况下,可选的链式操作员可以帮助我们避免访问未在地址中指定街道的用户街道时遇到错误。

const user = {};

console.log(user.address.street) // Error!
console.log(user?.address?.street) // undefined. No Error

Learn more

25.什么是阴影dom?

Shadow dom是一组Web标准,它允许在网页上封装元素的结构和样式。它代表了位于元素内部的DOM的特殊段,并与页面其余部分分开。 Shadow dom用于创建具有隔离和风格化内容的组件和小部件,与页面的整体结构不冲突。
Learn more

26.什么是递归?如何使用它?

递归是解决问题的一种方法,其中函数通过在其自身的功能主体中重新解决问题来解决问题。简而言之,这是一个函数自称的时候。

递归函数包括:

  1. 终止条件或基本案例
  2. 递归步骤 - 将问题减少为更简单的形式的一种方法。
function factorial(x) {
   if (x === 0) {
      return 1;
   }
   return x * factorial(x - 1);
}

基本情况是必要的条件;否则,由于无限的函数调用循环,它将导致堆栈溢出。
Learn more

27.功能表达式和函数声明有什么区别?

函数声明是声明函数的传统方式。

function foo() {
    console.log('Hello World');
}

功能表达式:

let foo = function() {
    console.log('Hello World');
}

随着函数声明,与任何其他值一样,将创建函数并分配给变量。从本质上讲,它是如何定义函数的,因为它是存储在变量“ foo”中的值。但是,在执行代码块之前,对功能声明进行处理,这意味着它们在整个代码块中可见。另一方面,仅在执行流达到它们时才会创建函数表达式。

Learn more

28.什么是构造函数函数?

构造函数函数是用于创建对象的常规函数​​。但是,使用它们有两个规则:

  1. 构造函数的名称应从大写字母开始。
  2. 应使用新操作员调用构造函数函数。
function User(firstName, lastName) {
    this.firstName = firstName
    this.lastName = lastName
    this.role = 'user'
}

const user = new User('John', 'Johnson')
console.log(user.firstName) // John

使用新操作员创建构造函数函数时,会发生以下情况:

  1. 创建一个新的空对象并分配给此对象。
  2. 执行构造函数函数内的代码。通常,此代码将修改此对象并添加新属性。
  3. 返回的价值。

Learn more

29.如何从对象中获取键列表和值列表?

您可以使用object.keys()获取键和object.values()的列表以获取值列表。

const user = {
    firstName: 'John',
    lastName: 'Johnson'
}

const keys = Object.keys(user)
const values = Object.values(user)

console.log(keys) // ['firstName', 'lastName']
console.log(values) // ['John', 'Johnson'] 

Learn more

30.提供ES6中新功能的示例。

最常见的:

  • 让和const。引入新的关键字,以用块范围来声明变量。
  • 箭头功能。箭头功能的概念允许更简洁明了的函数定义。
function add(a, b) { return a + b } // Regular function
const add = (a, b) => a + b // Arrow function
  • 默认参数。您可以为函数参数定义默认值。
function greet(name = 'Anonymous') { console.log(Hello, ${name}!) }
greet(); // "Hello, Anonymous!"
greet('John') // "Hello, John!"
  • 传播操作员(...)。传播操作员允许为函数参数或创建新的数组/对象解开包装数组或对象元素。
const numbers = [1, 2, 3];
console.log(...numbers) // 1 2 3
const array1 = [1, 2, 3]; 
const array2 = [...array1, 4, 5] // [1, 2, 3, 4, 5]
  • 破坏性。破坏允许从数组或对象中提取值并将其分配给变量。
const person = { name: 'John', age: 30, city: 'London' }
const { name, age } = person;
console.log(name, age) // "John 30"
const numbers = [1, 2, 3]
const [first, second] = numbers;
console.log(first, second); // 1 2

Learn more

31.如何在ES6中执行班级继承?

类继承是使用“扩展”关键字完成的,然后是父类的名称。

class User {
    firstName = 'John'
    lastName = 'Johnson'
}

class Customer extends User {
    cart
}

Learn more
And even more

32. JavaScript中的微型和宏任务是什么?

在JavaScript中,Microtasks和Macrotasks是指在事件循环中需要执行的任务类型。 MicroTask是在浏览器重新粉刷页面之前需要在当前事件循环中执行的任务。通常,它们使用promise....chen(),process.nexttick()(在node.js)或mutationObserver等方法添加到执行队列中。微型杀剂的示例包括执行承诺处理程序和DOM突变。另一方面,宏观施加是在当前事件循环完成和在屏幕上进行更改之前需要执行的任务。这包括使用Settimeout,setInterval,requestAnimationFrame以及处理输入事件和网络请求的任务。在处理当前事件循环中的所有微型箱后,执行宏大。 MicroTasks和Macrotasks之间的差异很重要,因为它决定了执行顺序,并允许在JavaScript中管理不同任务的优先级。 MicroTasks具有更高的优先级,并且在Macrotasks之前执行,这允许更快的接口更新并防止阻止主JavaScript执行线程。
Learn more

33.什么是发电机?

发电机根据需要产生一系列值。发电机与对象合作良好,并使其易于创建数据流。

要声明生成器,使用了特殊的语法 - 生成器函数。

function* generateSomething() {
    yield 10;
    yield 20;
    yield 30;
    return 40;
}

next()是生成器的主要方法。当调用时,Next()开始执行代码直至最近的收益率语句。该值可能不存在,在这种情况下,它表示为未定义。当达到收益率时,函数执行暂停,并将相应的值返回到外部代码。

let generator = generateSomething();
let first = generator.next();

Learn more

34.将数据存储在浏览器中的方法是什么?

有几种将数据存储在浏览器中的方法:

  • LocalStorage和SessionStorage-将键值对存储在浏览器中。在刷新页面后,保留存储的数据。这两个存储选项都只能将字符串用作键和值,因此需要使用json.stringify()。
  • 将对象转换为
  • cookie-浏览器中存储的一小部分数据字符串。 cookie通常使用set-cookie标头通过Web服务器设置。然后,浏览器将使用cookie标头自动将它们添加到同一域中的每个请求。一个cookie最多可以容纳4KB的数据。根据浏览器,每个站点允许20多个cookie。
  • indexedDB-一个内置数据库,比localstorage更强大。这是一个钥匙值商店,可以使用多种类型的密钥,并且值几乎可以是任何东西。 IndexEdDB支持可靠性的交易,支持关键范围查询和索引,并允许与LocalStorage相比,存储更多的数据。 IndexedDB专为离线应用程序而设计,可以与服务工作者和其他技术结合使用。

Learn more
Learn more
Learn more

35. SessionStorage和LocalStorage有什么区别?

sessionstorage和localstorage允许在浏览器中以键值格式存储对象。
主要区别是:

  • LocalStorage可以存储多达10 MB的数据,而SessionStorage最多可以存储5 MB。
  • localStorage中的数据未删除,当关闭浏览器选项卡时会删除SessionStorage中的数据。
  • 来自LocalStorage的数据可从任何窗口访问,而SessionStorage的数据仅可从同一浏览器窗口访问。 Learn more

36.什么是正则表达式?

正则表达式是由特殊规则和模式定义的字符串。它们是一个强大的工具,可检测并使用字符串中的复杂结构。

let str = "We will, we will rock you"

console.log(str.match(/we/gi)) // ['We', 'we']

Lean more

37.什么是弱图和弱图,它们与地图和集合有何不同?

弱图和地图之间的第一个区别在于,弱图中的密钥必须是对象,而不是原始值。
第二个区别在于数据结构的存储器存储。 JavaScript引擎只要可以使用,就可以将值保持在内存中,这意味着可以使用它们。
通常,即使存在数据结构,也可以将对象属性,数组元素或其他数据结构视为可触及的,并且只要存在数据结构,即使没有其他参考。
在虚弱和弱点的情况下,它的工作方式不同。一旦对象变得无法到达,就将其从数据结构中删除。

Learn more

38.为什么两个具有相同字段的对象在比较时返回false?

基于对内存区域的引用进行比较。对于JavaScript,即使具有相同的字段,test1和test2对象也不同。仅当对象是同一对象时。

const test1 = { value: 3 }
const test2 = { value: 3 }
console.log(test1 == test2) // false

39.为什么我们可以调用原始类型的方法?

JavaScript允许使用原始数据类型 - 字符串,数字等 - 好像它们是对象一样。原始数据类型具有方法。
为了使此功能可用,每个原始数据类型都有其自己的包装对象:字符串,数字,布尔值和符号。多亏了这些包装器对象,原始数据类型具有不同的方法集,例如TolowerCase()或ToupperCase()。

Learn more

40.如何从创建一个对象?

您可以通过使用实例运算符来检查哪个类是一个对象,请考虑继承。

class Person {}
const person = new Person()
console.log(person instanceof Person) // true

Learn more

41.编写代码,该代码将在每10秒钟内登录一次在网站上花费的时间。

let time = 0
setInterval(() => {
    time += 10
    console.log(time)
}, 10000)

Learn more

42.什么是纯函数?

纯函数是满足两个条件的函数:

  1. 每次使用相同的参数调用函数时,它都会返回相同的结果。
  2. 它没有副作用,这意味着它不会修改函数之外的变量。
function calculate(num) {
    return calculate * 0.05;
}
console.log(calculate(15)) 
//calculate() function will always return the same result if we pass the same parameter

43.什么是高阶功能?

高阶函数是一个将另一个函数作为参数或结果返回函数的函数。

const nums1 = [1, 2, 3]
const nums2 = nums1.map(function(num) {
    return num * 2;
})
console.log(nums2) // [2, 4, 6]

44.如果我们可以使用回调处理异步代码,为什么需要承诺?

如果我们想使用回调函数从服务器中获取一些数据,则将导致以下内容:

func((x) => {
  anotherFunc(x, (y) => {
    andAnotherFunc(i, (j) => {
      // some code
    })
  })
})

这被称为回调地狱,因为每个回调都嵌套在另一个回调,每个回调都取决于父函数。

使用承诺,我们可以重写上面的代码:

func()
.then((x) => {
  return anotherFunc(x)
})
.then((y) => {
  return andAnotherFunc(y)
})
.then((i) => {
  return i
})

有了承诺,执行顺序很明确,使代码更可读。
Learn more

45.编写自己的绑定方法实现。

要实现它,我们可以使用闭合和应用()方法将函数绑定到上下文。

function bind(context, func) {
  return function(...args) {
    func.apply(context, args)
  }
}

46.用方法加上计算器函数,负,乘,分隔和get。该功能必须通过可选的链式起作用。

function calculator() {
  let result = 0;

  function plus(val) {
    result += val;
    return this;
  }

  function minus(val) {
    result -= val;
    return this;
  }

  function divide(val) {
    result /= val;
    return this;
  }

  function multiply(val) {
    result *= val;
    return this;
  }

  function get() {
    console.log(result);
    return this;
  }

  return { plus, minus, divide, multiply, get };
}

let calc = calculator();
calc.plus(2).minus(1).plus(19).divide(2).multiply(3).get(); // 30

47.编写一个随机函数,该函数采用数字数组并按随机顺序对数组进行分类。

您可以使用sort()方法和m nath.random()为此。

function randomSort(array) {
  return array.sort(() => {
    return 0.5 - Math.random();
  });
}
const arr = [2, 1, 3, -2, 9]
console.log(randomSort(arr)) // [-2, 2, 1, 3, 9]
console.log(randomSort(arr)) // [2, 1, -2, 9, 3]
console.log(randomSort(arr)) // [-2, 1, 9, 2, 3]
console.log(randomSort(arr)) // [1, -2, 2, 3, 9]

48.编写一个删除式值函数,该函数采用二维数组,并从每个嵌套数组中删除最大数字。

我们应该迭代每个嵌套数组,获取每个嵌套数组的最大值并删除它。

function deleteGreatestValue(array) {
  for (let i = 0; i < array.length; i++) {
    const max = Math.max(...array[i]);
    const maxIndex = array[i].indexOf(max);
    array[i].splice(maxIndex, 1);
  }
  return array;
}

const arr = [[1, 4, 4], [2, 6, 3], [9, 2, 7]]
console.log(deleteGreatestValue(arr)) // [[1, 4], [2, 3], [2, 7]]

49.编写一个sortpeople函数,该函数采用一系列字符串名称和数字高度,其中名称[i] == heights [i]。它应该根据高度数组对名称数组进行排序。

function sortPeople(names, heights) {
  const array = [];
  for (let [i, name] of names.entries()) {
    array.push([name, heights[i]]);
  }
  return array.sort((a, b) => b[1] - a[1]).map(([name]) => name);
}
const names = ['John', 'Maria', 'Alexa', 'Robert']
const heights = [180, 160, 165, 187]
console.log(sortPeople(names, heights)) // ['Robert', 'John', 'Alexa', 'Maria']

50.编写一个子集函数,该功能占用数字数字,并返回这些数字的所有可能变化。

function subsets(nums) {
  let result = [[]];

  for (let num of nums) { // Iterate through each number in the nums array
    const currentSize = result.length; // Get the current size of result to use it in the loop.

    for (let i = 0; i < currentSize; i++) {
      let subArray = [...result[i], num]; // Create a new subarray by adding the current number to the result[i] element.
      result.push(subArray);
    }
  }

  return result; // Return all possible variations of arrays from the numbers.
}

51.如何扭转链接列表?

让我们创建一个函数反向链接列表,该列表以链接列表为输入,并返回该列表的相反版本。

方法:

  1. 它用null初始化结果变量,该变量将保存相反的列表。
  2. 它用头将根变量初始化,该变量指向列表的开始。
  3. 它进入一个段循环,直到root变为null,指示列表的结尾。
  4. 在循环内,它检查结果是否已经具有元素。如果确实如此,它将创建一个带有当前值root.val和指向下一个节点结果的指针的新列表节点。然后,它使用此新节点更新结果。
  5. 如果结果还没有任何元素,它将创建一个带有当前值root.val和null的新列表节点作为下一个节点的指针。然后,它使用此新节点更新结果。
  6. 更新结果后,它通过将root.next分配给根。
  7. 将其移至列表中的下一个元素。
  8. while循环完成后,它返回了存储在结果中的反向列表。

总而言之,该函数通过每个节点从头部到尾部迭代,扭转链接列表,为每个值创建一个新列表节点并相应地更新指针。

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */

function reverseLinkedList(node) {
  let result = null; // Initialize the result variable with null, it will hold the reversed list.
  let root = head; // Initialize the root variable with head, pointing to the start of the list.

  // While root is not null (until we reach the end of the list)
  while (root) {
    if (result) { // If result already has elements
      result = new ListNode(root.val, result); // Create a new list node with the current value root.val and a pointer to the next node result. Update result.
    } else { // If result doesn't have any elements yet...
      result = new ListNode(root.val, null); // Create a new list node with the current value root.val and null as the pointer to the next node. Update result.
    }
    root = root.next; // Move to the next element in the list.
  }
  return result; // Return the reversed list.
}

52.如何对链接列表进行排序?

让我们创建一个函数sortlist,将链接列表作为输入列出,并返回该列表的排序版本。

方法:

  1. 检查给定的链接列表是否为空。
  2. 穿越链接列表并将节点值存储到数组中。
  3. 使用内置sort()方法对数组进行排序。
  4. 使用排序的数组创建一个新的链接列表。
  5. 返回创建的链接列表的头。
/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
function sortList (head) {
  if (!head) {
    return null;
  }
  let root = head;
  let arr = [];

  while(root){
    arr.push(root.val);
    root = root.next;
  }
  arr.sort((a, b) => a - b);

  let node = new ListNode(arr[0]);
  head = node;

  let temp = head;

  for(let i = 1; i < arr.length; i++){
    let node = new ListNode(arr[i]);
    temp.next = node;
    temp = temp.next;       
  }
  return head;
};

结论

为这些问题做准备,研究涵盖的主题以及审查相关资源可以提高您成功通过面试的机会。
感谢您阅读本文,希望您获得了新的知识。

我期待您的反应和评论。
祝您面试好运!