2024 全新 Javascript 面试题目基础篇

news2024/11/26 3:39:36

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.coloradmin.cn/o/1709106.html

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

相关文章

git将某次提交合并到另一个分支

一、需求背景 将分支b中的某一次提交单独合并到分支a 二、实现方案 需求:将分支b中的某一次提交单独合并到分支a 1.在git上查看指定某次提交的id,如下图所示: 也可以通过git log命令查看提交的id,如下图: git log…

K8s集群调度续章

目录 一、污点(Taint) 1、污点(Taint) 2、污点组成格式 3、当前taint effect支持如下三个选项: 4、查看node节点上的污点 5、设置污点 6、清除污点 7、示例一 查看pod状态,模拟驱逐node02上的pod …

前端笔记-day07

学成在线网站 文章目录 效果图代码展示index.htmlindex.cssbase.css 效果图 代码展示 index.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-w…

鸿蒙学习第一课--认识目录结构

项目结构介绍 module.json5 src > main > module.json5&#xff1a;Stage模型模块配置文件。主要包含HAP包的配置信息、应用/服务在具体设备上的配置信息以及应用/服务的全局配置信息。具体的配置文件说明&#xff0c;详见module.json5配置文件。 资源分类和访问 关于s…

Oracle EBS API创建AP发票报错:ZX_TAX_STATUS_NOT_EFFECTIVE和ZX_REGIME_NOT_EFF_IN_SUBSCR-

背景 由创建国外业务实体财务未能提供具体国家地区会计税制&#xff0c;而是实施人员随便选择其它国外国家地区会计税制。导致客户化创建AP发票程序报错&#xff1a;UNEXPECTED TAX ERROR-导入时出现意外的税务错误ZX_TAX_STATUS_NOT_EFFECTIVE-ZX_REGIME_NOT_EFF_IN_SUBSCR-ZX…

MagicLens:新一代图像搜索技术和产品形态

MagicLens&#xff1a;Self-Supervised Image Retrieval with Open-Ended Instructions MagicLens: 自监督图像检索与开放式指令 作者&#xff1a;Kai Zhang&#xff0c; Yi Luan&#xff0c; Hexiang Hu&#xff0c; Kenton Lee&#xff0c; Siyuan Qiao&#xff0c; Wenhu …

SQL刷题笔记day5

SQL218题目 我的错误代码&#xff1a; select de.dept_no,de.emp_no,s.salary from employees e join dept_emp de on de.emp_no e.emp_no join salaries s on s.emp_no e.emp_no where de.dept_no not in dept_manager.dept_no #not in 好像不能直接这样用 这里报错 正确代…

ysoserial下载和使用

1.下载网址 GitHub - frohoff/ysoserial: A proof-of-concept tool for generating payloads that exploit unsafe Java object deserialization. 2.使用 因为要用java打开jar格式的&#xff0c;所以如果下的是源文件&#xff0c;还需要打包&#xff0c;我试了试&#xff0c…

路径规划算法--BFS

系列文章目录 文章目录 系列文章目录一、BFS二、BFS伪代码BFS与Dijkstra区别 一、BFS BFS&#xff08;Breadth First Search&#xff09;为广度优先搜索&#xff0c;是一种用于遍历或搜索树或图的搜索算法&#xff0c;适用于无权图的遍历。BFS从根节点开始&#xff0c;探索其相…

揭秘Tensor Core黑科技:如何让AI计算速度飞跃

揭秘 Tensor Core 底层&#xff1a;如何让AI计算速度飞跃 Tensor Core&#xff0c;加速深度学习计算的利器&#xff0c;专用于高效执行深度神经网络中的矩阵乘法和卷积运算&#xff0c;提升计算效率。 Tensor Core凭借混合精度计算与张量核心操作&#xff0c;大幅加速深度学习…

B站大数据分享视频创作300天100+原创内容4000+粉

以今年五一作为一个里程碑参考点&#xff0c;给明年一个可以比较的数据。 我正经发力创作是2023.06.17 (前面几个视频是试水)&#xff0c;300天不到一年时间 创作了100原创数据相关视频&#xff0c;创作频率应该很高了&#xff0c;收获了下面几个数字&#xff0c;审视自身&…

K-means 聚类模型详解

K-means 聚类模型详解 K-means 是一种常用的无监督学习算法&#xff0c;用于将数据集分成 K 个簇。其目标是最小化各个簇内数据点到簇中心的距离平方和。K-means 广泛应用于图像压缩、市场细分、模式识别等领域。 算法步骤 初始化: 随机选择 K 个初始簇中心&#xff08;质心…

富港银行 优惠链接 邀请码 兑换码 优惠码 分享

首次记得一定要点击链接注册&#xff0c;注册开户费50美金 限时&#xff01;优惠开通国际银行账户&#xff01; cbi帐户管理费&#xff1a;10美元/月&#xff0c;余额>500美元&#xff0c;1美元/月/&#xff0c;余额>2000美元&#xff0c;0美元/月。 一定要显示50的时候…

牛!华为《Linux 面试笔记大全》太赞了,完整版PDF 开放下载!

在QQ和微信社群中&#xff0c;我注意到许多人都在寻找一份全面的Linux学习资料。因此&#xff0c;我在这里为大家整理和分类了相关的信息&#xff0c;可以看作是对重点内容的梳理和归纳。 这份《Linux面试笔记》主要分为三大部分&#xff1a;基础篇-进阶篇-高级篇 本书笔记针…

基于SpringBoot的本科生考研率统计系统

基于SpringBoot的本科生考研率统计系统 一、开发技术二、功能模块三、代码结构四、数据库设计五、运行截图六、源码获取 一、开发技术 技术&#xff1a;SpringBoot、MyBatis-Plus、Redis、MySQL、Thymeleaf、Html、Vue、Element-ui。 框架&#xff1a;基于开源框架easy-admin开…

【前端学习笔记】HTML基础

HTML 一、HTML介绍1.HTML概念2.文档声明3.字符编码4. HTML标签5. HTML属性 二、标签1.meta标签2.语义标签3.布局标签4.列表5.超链接6.图片7.字符实体8.内联格式9.HTML 表格10.HTML 表单 三、HTML5新特性1. 本地存储2. Cookie3. 语义化标签4.多媒体元素5.表单增强6.Canvas7.SVG …

【云原生_K8S系列】认识 Kubernetes

在当今数字化转型的浪潮中&#xff0c;企业对于构建高效、灵活的软件架构有了更高的期望。而在这个迅速变化的环境中&#xff0c;容器化技术如雨后春笋般涌现&#xff0c;为解决传统部署和管理软件所带来的挑战提供了一种全新的解决方案。在众多容器编排工具中&#xff0c;Kube…

2024年4月—马克思主义基本原理概论真题及答案解析(上海自考)

目录 1.选择题 2.简答题 3.论述题 1.选择题 2.简答题

“盲人独立生活技能提升方案”:科技点亮希望之光

在追求平等与包容的社会进程中&#xff0c;盲人群体的独立生活能力提升成为了重要议题。随着科技的飞速发展&#xff0c;一款名为“蝙蝠避障”的辅助软件应运而生&#xff0c;以其独特的实时避障和拍照识别功能&#xff0c;为盲人在旅行乃至日常生活中开辟了新的可能。这不仅是…

社会工程学:美色你顶得住吗?

背景 近年来&#xff0c;网络钓鱼的手段是屡见不鲜&#xff0c;手段和方式也是层出不穷。钓鱼相关的技术作为一种比较高效的打点方式&#xff0c;越来越多的应用于红蓝对抗当中。本文主要分享一次实战攻防中几个有趣的钓鱼场景。 重点说明&#xff1a;本文分享内容为一次经过授…