2024 全新 Javascript 面试题目基础篇

1. JavaScript 是单线程的吗?

没错,JavaScript 是 一种 单线程语言。这意味着它只有 一个调用栈和一个内存堆。每次只执行一组指令。

此外,JavaScript 是同步和阻塞 的性质。这意味着代码是逐行执行的,一个任务必须在下一个任务开始之前完成。

然而,JavaScript 也具有异步能力,允许某些操作独立于主执行线程执行。这通常通过回调、Promise、async/await 和事件监听器等机制实现。这些异步特性使 JavaScript 能够处理诸如获取数据、处理用户输入和执行 I/O 操作等任务,而不会阻塞主线程,使其适用于构建响应式和交互式的 Web 应用程序。

2. 解释 JavaScript 引擎的主要组件及其工作原理。

每个浏览器都有一个 JavaScript 引擎,用于执行 JavaScript 代码并将其转换为机器码。

当执行 JavaScript 代码时,解析器首先读取代码并生成 AST,然后将其存储在内存中。解释器接着处理这个 AST 并生成字节码或机器码,计算机执行它。

性能分析器是 JavaScript 引擎的一个组件,监视 代码的执行情况。

字节码与性能分析数据一起被优化编译器使用。 “优化编译器” 或即时 (JIT) 编译器根据性能分析数据做出某些假设,并生成高度优化的机器码。

有时候,“优化” 的假设是不正确的,然后它通过 “取消优化” 阶段(对我们来说实际上会产生开销)回到之前的版本。

JS 引擎通常会优化 “热门函数”,并使用内联缓存技术优化代码。

在此过程中,调用栈跟踪当前正在执行的函数,内存堆用于内存分配

最后,垃圾收集器开始管理内存,从未使用的对象中回收内存。

Google Chrome 𝗩𝟴 引擎:

  1. 解释器称为 “Ignition”
  2. 优化编译器称为 “TurboFan”
  3. 除了解析器外,还有一个 “pre-parser” 用于检查语法和标记。
  4. 引入了 “Sparkplug”,位于 “Ignition” 和 “TurboFan” 之间,也称为 快速编译器

3. 解释 JavaScript 中的事件循环。

事件循环是 JavaScript 运行时环境的核心组件。它负责调度和执行异步任务。事件循环通过持续监视两个队列来工作:调用栈和事件队列。

调用栈 是一个 堆栈(后进先出)数据结构,用于存储当前正在执行的函数(存储代码执行期间创建的执行上下文)

Web API 是异步操作(setTimeout、fetch 请求、Promise)和它们的回调等待完成的地方。它从线程池中借用线程以在后台完成任务,而不会阻塞主线程。

作业队列(或微任务) 是一个 先进先出 结构,其中包含 准备执行的异步/等待、Promise、process.nextTick() 的回调。例如,已完成 Promise 的 resolve 或 reject 回调会排队在作业队列中。

任务队列(或宏任务) 是一个 先进先出 结构,其中包含 准备执行的异步操作的回调(类似于定时器 setInterval、setTimeout)。例如,已超时的 setTimeout() 的回调 - 准备执行 - 会排队在任务队列中。

事件循环持续监视 调用栈是否为空。如果调用栈为空,事件循环会查看作业队列或任务队列,并将准备执行的任何回调 出队到调用栈中执行

4. JavaScript 中的不同数据类型

JavaScript 是一种动态且松散类型(也称鸭子类型)的语言。这意味着我们不需要指定变量的类型,因为 JavaScript 引擎会根据变量的值动态确定变量的数据类型。

JavaScript 中的原始数据类型是最基本的数据类型,表示单一值它们是不可变的(无法更改),直接包含特定的值。

在 JavaScript 中,Symbol 是一种原始数据类型,在 ECMAScript 6 (ES6) 中引入,表示唯一且不可变的值。它通常用于作为对象属性的标识符,以避免命名冲突。

const mySymbol = Symbol('key');  
const obj = {  [mySymbol]: 'value'  
};

当 Symbol 被用作属性键时,它不会与其他属性键(包括字符串键)发生冲突。

5. 什么是回调函数和回调地狱?

在 JavaScript 中,回调通常用于处理异步操作。

回调函数 是一种作为参数传递给另一个函数并在特定任务完成或特定时间执行的函数。

function fetchData(url, callback) {  // 模拟从服务器获取数据  setTimeout(() => {  const data = 'Some data from the server';  callback(data);  }, 1000);  
}  function processData(data) {  console.log('Processing data:', data);  
}  fetchData('https://example.com/data', processData);

在这个例子中,fetchData 函数接受一个 URL 和一个回调函数作为参数。在从服务器获取数据后(使用 setTimeout 模拟),它调用回调函数并将检索到的数据传递给它。

回调地狱,也称为**“金字塔地狱”**,是指在 JavaScript 编程中,当多个嵌套回调用于异步函数时,会产生代码难以阅读和维护的情况。

它发生在异步操作依赖于先前异步操作的结果时,导致深度嵌套且难以阅读的代码。

回调地狱是一种反模式,包含多个嵌套回调,这使得处理异步逻辑的代码难以阅读和调试。

fs.readFile('file1.txt', 'utf8', function (err, data) {  if (err) {  console.error(err);  } else {  fs.readFile('file2.txt', 'utf8', function (err, data) {  if (err) {  console.error(err);  } else {  fs.readFile('file3.txt', 'utf8', function (err, data) {  if (err) {  console.error(err);  } else {  // 继续更多的嵌套回调...  }  });  }  });  }  
});

在这个例子中,我们使用 fs.readFile 函数顺序读取三个文件,每个文件读取操作都是异步的。结果,我们不得不将回调嵌套在一起,形成一个回调金字塔。

为了避免回调地狱,现代 JavaScript 提供了像 Promise 和 async/await 这样的替代方案。 这里是使用 Promise 的相同代码:

const readFile = (file) => {  return new Promise((resolve, reject) => {  fs.readFile(file, 'utf8', (err, data) => {  if (err) {  reject(err);  } else {  resolve(data);  }  });  });  
};readFile('file1.txt')  .then((data1) => {  return readFile('file2.txt');  })  .then((data2) => {  return readFile('file3.txt');  })  .then((data3) => {  // 继续处理更多基于 promise 的代码...  })  .catch((err) => {  console.error(err);  });

6. 什么是 Promise 和 Promise 链?

Promise: Promise 是 JavaScript 中用于异步计算的对象它代表一个异步操作的结果,这个结果可能是已解决或已拒绝的

Promise 有三种状态:

  1. Pending(等待中):初始状态。在此状态下,Promise 的最终值尚不可用。
  2. Fulfilled(已解决):Promise 已成功解决,最终值现在可用。
  3. Rejected(已拒绝):Promise 遇到错误或被拒绝,最终值不可用。

Promise 构造函数 有两个参数 (resolve, reject),它们是函数。如果异步任务没有错误地完成,则调用 resolve 函数并传递消息或获取的数据以解决 promise。如果发生错误,则调用 reject 函数并传递错误信息。

我们可以使用 .then() 方法来访问 promise 的结果,并且可以使用 .catch() 方法来捕获错误。

// 创建一个 Promise  
const fetchData = new Promise((resolve, reject) => {  // 模拟从服务器获取数据  setTimeout(() => {  const data = 'Some data from the server';  // 使用获取的数据解决 Promise  resolve(data);  // 使用错误信息拒绝 Promise  // reject(new Error('Failed to fetch data'));  }, 1000);  
});  // 使用 Promise  
fetchData  .then((data) => {  console.log('Data fetched:', data);  })  .catch((error) => {  console.error('Error fetching data:', error);  });

Promise 链:执行一系列异步任务的方法,通过使用 promise 按顺序一个接一个地执行异步任务,称为 Promise 链。

它涉及将多个 .then() 方法链接到一个 Promise 以按特定顺序执行一系列任务。

new Promise(function (resolve, reject) {  setTimeout(() => resolve(1), 1000);  
})  .then(function (result) {  console.log(result); // 1  return result * 2;  })  .then(function (result) {  console.log(result); // 2  return result * 3;  })  .then(function (result) {  console.log(result); // 6  return result * 4;  });

7. 什么是 async/await?

Async/await 是处理 JavaScript 中异步代码的现代方法。它提供了一种更简洁和可读的方式来处理 Promise 和异步操作,有效地避免了“回调地狱”,并改善了异步代码的整体结构。

在 JavaScript 中,async 关键字用于定义一个异步函数,该函数返回一个 Promise

在异步函数中,await 关键字用于暂停函数的执行,直到 Promise 被解决,有效地使代码看起来像是同步的,同时处理异步操作。

async function fetchData() {  try {  const data = await fetch('https://example.com/data');  const jsonData = await data.json();  return jsonData;  } catch (error) {  throw error;  }  
}  // 使用异步函数  
fetchData()  .then((jsonData) => {  // 处理获取的数据  })  .catch((error) => {  // 处理错误  });

在这个例子中,fetchData 函数被定义为一个异步函数,它使用 await 关键字暂停执行并等待 fetchjson 操作,实际工作时像处理同步代码一样处理 Promise。

8. ===== 运算符有啥区别?

==(宽松相等运算符):这家伙会进行类型转换,意味着在比较之前会把操作数转化为相同的类型。它只检查值是否相等,而不考虑它们的数据类型。比如,1 == '1' 会返回 true,因为 JavaScript 在比较前会把字符串 '1' 转换为数字。

===(严格相等运算符):这个就讲究多了,不进行类型转换,直接比较。它不仅看值是否相等,还要求数据类型一样。所以 1 === '1' 就会返回 false,毕竟一个是数字,另一个是字符串嘛。

简单说,== 比较时会“睁一只眼闭一只眼”,而 === 则是严格的“一视同仁”,连类型都得一样。

执行效率上,== 相比 === 会快一点点哦。

几个例子帮你感受下这俩的区别:

0 == false   // true  
0 === false  // false  
1 == "1"     // true  
1 === "1"    // false  
null == undefined // true  
null === undefined // false  
'0' == false // true  
'0' === false // false  
[]==[] 或者 []===[] // 都是 false,因为指向不同的内存对象  
{}=={} 或者 {}==={} // 同样都是 false,每个花括号都代表独一无二的对象

9. 在 JavaScript 中创建对象有几种方法?

JavaScript 创建对象的方法多着呢,这里给你数数常见的几种:

a) 对象字面量:最直接的方式,用花括号 {} 把属性和方法一股脑儿包起来。

let person = {  firstName: '约翰',  lastName: '杜',  greet: function() {  return '你好,' + this.firstName + ' ' + this.lastName;  }  
};

b) 构造函数:用 new 关键字调用构造函数,可以创建多个实例,属性和方法通过 this 分配。

function Person(firstName, lastName) {  this.firstName = firstName;  this.lastName = lastName;  this.greet = function() {  return '你好,' + this.firstName + ' ' + this.lastName;  };  
}  let person1 = new Person('约翰', '杜');  
let person2 = new Person('简', '史密斯');

c) Object.create():这个方法允许你指定一个原型对象来创建新对象,对原型控制更精细。

let personProto = {  greet: function() {  return '你好,' + this.firstName + ' ' + this.lastName;  }  
};  let person = Object.create(personProto);  
person.firstName = '约翰';  
person.lastName = '杜';

d) ES6 的 Class 语法:新潮的 ES6 引入了类的概念,用 class 关键字定义对象和方法,看起来更正规了。

class Person {  constructor(firstName, lastName) {  this.firstName = firstName;  this.lastName = lastName;  }  greet() {  return '你好,' + this.firstName + ' ' + this.lastName;  }  
}  let person = new Person('约翰', '杜');

e) 工厂函数:这类函数能“生产”对象,返回一个对象实例,方便定制属性。

function createPerson(firstName, lastName) {  return {  firstName: firstName,  lastName: lastName,  greet: function() {  return '你好,' + this.firstName + ' ' + this.lastName;  }  };  
}  let person1 = createPerson('约翰', '杜');  
let person2 = createPerson('简', '史密斯');

f) Object.setPrototypeOf():这个方法能给已存在的对象设置原型,提供另一种调整原型链的方式。

let personProto = {  greet: function() {  return '你好,' + this.firstName + ' ' + this.lastName;  }  
};  let person = {};  
person.firstName = '约翰';  
person.lastName = '杜';  
Object.setPrototypeOf(person, personProto);

g) Object.assign():通过拷贝源对象的所有可枚举自有属性到目标对象,实现对象合并或浅拷贝。

let target = { a: 1, b: 2 };  
let source = { b: 3, c: 4 };  
let mergedObject = Object.assign({}, target, source);

h) 原型继承:JavaScript 的精髓之一,通过构造函数的 .prototype 属性或类定义共享行为。

function Animal(name) {  this.name = name;  
}  Animal.prototype.greet = function() {  return '你好,我是 ' + this.name;  
};  function Dog(name, breed) {  Animal.call(this, name);  this.breed = breed;  
}  Dog.prototype = Object.create(Animal.prototype);  
Dog.prototype.constructor = Dog;  let myDog = new Dog('麦克斯', '贵宾犬');

i) 单例模式:保证一个类只有一个实例,常用闭包和立即执行函数表达式(IIFE)实现。

let singleton = (() => {  let instance;  function createInstance() {  return {  // 属性和方法  };  }  return {  getInstance: () => {  if (!instance) {  instance = createInstance();  }  return instance;  }  };  
})();

10. 什么是展开(Spread)和剩余(Rest)运算符?

剩余运算符...),在函数参数列表中使用时,可以把一堆传入的参数收集到一个数组里。这样,你就可以向函数传递任意数量的参数,无需一一列出它们的名字。

function 加和(...数字们) {  return 数字们.reduce((总数, 当前数) => 总数 + 当前数, 0);  
}  
console.log(加和(1, 2, 3, 4)); // 输出 10

展开运算符,同样用三个点(...),不过这次是把数组或对象的元素“拆开”到另一个数组或对象里。有了它,复制数组、拼接数组、合并对象都变得轻而易举。

const 数组1 = [1, 2, 3];  
const 数组2 = [4, 5, 6];  
const 合并数组 = [...数组1, ...数组2];  
// 合并数组是 [1, 2, 3, 4, 5, 6]const 对象1 = { a: 1, b: 2 };  
const 对象2 = { b: 3, c: 4 };  
const 合并对象 = { ...对象1, ...对象2 };  
// 合并对象是 { a: 1, b: 3, c: 4 }

11. 高阶函数是啥?

高阶函数在 JavaScript 中,就是要么接受一个或多个函数作为参数,要么返回一个函数作为结果,或者两者兼备。说白了,它处理的就是函数本身,要么把函数当“食材”用,要么产出函数这个“成品”。

function 数组操作(数组, 处理函数) {  let 结果 = [];  for (let 元素 of 数组) {  结果.push(处理函数(元素));  }  return 结果;  
}  function 乘以二(x) {  return x * 2;  
}  let 数字们 = [1, 2, 3, 4];  
let 两倍数字们 = 数组操作(数字们, 乘以二);  
console.log(两倍数字们); // 输出 [2, 4, 6, 8]

它们使得函数组合、柯里化、基于回调的异步操作成为可能,是写出优雅且函数式风格 JavaScript 代码的关键。

单参数函数(即一元函数),是指恰好接收一个参数的函数。就像它的名字那样,独来独往,只接受一个“客人”。

总结

今天,咱们主要学习了一些关于Javascript的基础知识,设计基本的事件循环、如何进行异步编程,解释了JavaScript中=====的区别、创建对象的多种方法、剩余与展开运算符的用法,以及高阶函数的概念。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/18191.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JVM的相关知识

目录 JVM内存划分 类加载过程 类加载中的“双亲委派模型” JVM内存划分 JVM也就是java进程。这个进程一旦跑起来之后,就会从操作系统里,申请一大块内存空间。JVM接下来就要进一步的对这个大的空间进行划分。划分成不同区域,从而每个区域都…

如何实时掌握手机号状态的API利器分析

在移动互联网的时代,手机号码不仅是通信的连接点,也是用户身份的关键识别。手机状态查询API 通过提供实时的手机号码状态查询服务,协助企业和组织更有效地管理用户信息,提升服务流程。 手机状态查询API 通过与电信运营商的数据库进…

Golang | Leetcode Golang题解之第117题填充每个节点的下一个右侧节点指针II

题目: 题解: func connect(root *Node) *Node {start : rootfor start ! nil {var nextStart, last *Nodehandle : func(cur *Node) {if cur nil {return}if nextStart nil {nextStart cur}if last ! nil {last.Next cur}last cur}for p : start; …

学至乎没而后止也

开场白 学至后没而后止也这个题目的原话来自与荀子《劝学》。大家知道什么意思吗?学习要学到你人没了,才算停止了。通俗点说就是只要没学死就往死里学,高雅点说就是要保持终身学习。 在以前说终身学习好像是一种良好习惯或品德,…

43-2 Linux入侵排查实验

环境准备: 老规则,我没有靶场就自己搭建了类似, 这里准备一台CentOS 7虚拟机作为受害者,然后使用CS制作木马并在受害者主机上线,具体过程可以看我之前写的一篇文章: 黑客必备利器:如何在系统上安装和使用 CobaltStrike(简称:CS)_cobalt strike-CSDN博客 最终的效果…

CANDela studio之CDDT与CDD

CDDT有更高的权限,作为模板规范CDD文件。 CDD可修改的内容比CDDT少。 CDDT根据诊断协议提供诊断格式,主要就是分类服务和定义服务,一般是OEM释放,然后由供应商细化成自己零部件的CDD文件。 在这里举个例子,OEM在CDDT…

Java | Leetcode Java题解之第117题填充每个节点的下一个右侧节点指针II

题目: 题解: class Solution {Node last null, nextStart null;public Node connect(Node root) {if (root null) {return null;}Node start root;while (start ! null) {last null;nextStart null;for (Node p start; p ! null; p p.next) {if…

AIGC中国开发者大会:AI Agent中国落地发展现状及多模态结合具身智能的发展展望

引言 2024年5月25日,第三届AIGC中国开发者大会在昆仑巢成功举办。本次大会围绕“AI Agent的国内应用现状及多模态结合具身智能的发展展望”这一主题,邀请了多位知名企业家、投资人以及技术专家,共同探讨大模型在中国各行各业的应用现状及未来…

AURIX TC3xx单片机介绍-启动过程介绍3

如下的内容是英文为主,对于TC3xx芯片启动原理不清楚的,可以给我留言,我来解答你们的问题! 3.2.1 Reset类型识别 Reset类型的识别是用来判断上次的复位是Application Reset还是System Reset还是CPU0 Reset。基于复位的原因,启动软件会运行不同的分支逻辑。复位原因可以通…

文章结尾,铺垫下一章带来的期待

你是否容易在阅读时打瞌睡? 是否有很多买回来的书,放在书架上一年甚至几年都未读完,积满了灰尘? 但是,对于小说和电视剧,你却完全停不下来。每集片尾的预告激发了你持续观看下一集的渴望,带来了无限的期待…… 当你撰写文章或编写工具书时,内容可能呈现出乏味的面貌…

pelican,一个超强的 Python 库!

更多Python学习内容:ipengtao.com 大家好,今天为大家分享一个超强的 Python 库 - pelican。 Github地址:https://github.com/getpelican/pelican 在当今数字化时代,博客已经成为个人和企业分享信息、展示成果的重要途径。静态网站…

熵值法(熵权法)

熵值法(Entropy Method)是一种多属性决策分析方法,主要用于权重确定、排序和评价。它在风险评估、资源配置、环境管理等领域得到广泛应用。熵值法的核心思想是基于信息熵的概念,利用信息熵来度量各属性对决策的贡献程度&#xff0…

FME学习之旅---day28

我们付出一些成本,时间的或者其他,最终总能收获一些什么。 教程:CSV 入门 逗号分隔值 (CSV) 是一种以 ASCII 文件格式存储结构化信息的方法,从而使其成为一个非常简单的数据库。这使其成为电子表格、数据…

【Qt秘籍】[004]-Qt中的重要工具-介绍

QtCreator概览 当我们打开系统的菜单翻到刚刚下载的Qt文件,里面的内容却让我们眼花缭乱。 不过别急,下面我们将一一解析。 1.Assistant Qt自带的离线版本官方文档 2.Designer Qt图形化设计界面的工具,通过拖拽控件快速生成界面&#xff0c…

Linux 基础笔记(一)

1.ctrl A : 到开头位置; 2.CtrlE : 到结尾位置; 3.ctrlU: 删除光标前内容; 4.ctrlK:删除光标后内容; 5.ctrlL: 清屏; 6.ctrlC:结束当前命令操作; 7.ctrlD:退出当…

2024 最新版 Navicat 17 下载与安装步骤及演示 (图文版)

Navicat 是一款专业的数据库管理工具,支持多种数据库类型,包括 MySQL、Oracle、SQL Server、PostgreSQL、MariaDB、Redis、MongoDB 和 SQLite。Navicat17包含的版本如下Navicat Premium 17, Navicat 17 for MySQL, Navicat 17 for Oracle, Navicat 17 fo…

YOLO算法输出图像含义以及理解

背景 近日使用YOLO算法进行目标检测任务的时候,对于输出的几张图片产生了疑惑,故在此复习与巩固。 图片说明 confusion_matrix(混淆矩阵): 混淆矩阵是一种用来衡量分类模型性能的表格。横坐标为实际真值&#xff0c…

CANDela studio使用小tips

打开软件的时候注意先选择英文,因为双击CDD/CDDT文件默认打开的是德文,所以最正确的打开方式是先打开CANDela studio,再导入CDD,不仅可以避免用德文打开,还能避免vector软件的bug。 不同的版本有不同的权限。 admin有…

TOPSIS综合评价

TOPSIS法(Technique for Order Preference by Similarity to an Ideal Solution)是一种常用的综合评价方法,该方法根据有限个评价对象与理想化目标的接近程度进行排序,是在现有的对象中进行相对优劣的评价。 TOPSIS法的原理是通过…

Java-文件操作

一、创建文件 1.创建文件夹 创建文件夹时,注意两个条件,该路径对应的是否为目录(dir),该文件夹是否存在。 File Apathnew File("./文件夹A"); //当前路径文件夹的存储路径if(!Apath.exists() &&am…