【面试题】JavaScript基础高频面试(上)

 1、简述JavaScript中map和foreach的区别?

`map`和`forEach`都是JavaScript数组的迭代方法,但它们之间存在一些关键区别。

1. 返回值:`map`方法会返回一个新的数组,这个新数组是由原数组通过某个函数处理后的结果组成的。而`forEach`方法则没有返回值,它仅仅是对数组中的每个元素执行一次给定的函数。

2. 修改原数组:`forEach`方法可以直接修改原数组,而`map`方法则不会改变原数组,而是创建一个全新的数组。

3. 性能:在大多数现代浏览器中,`map`的性能通常优于`forEach`。

让我们来看一个例子:

```javascript
let arr = [1, 2, 3, 4, 5];

// 使用map
let mapResult = arr.map(num => num * 2);
console.log(mapResult); // 输出:[2, 4, 6, 8, 10]
console.log(arr); // 输出:[1, 2, 3, 4, 5]

// 使用forEach
let forEachResult = [];
arr.forEach(num => forEachResult.push(num * 2));
console.log(forEachResult); // 输出:[2, 4, 6, 8, 10]
console.log(arr); // 输出:[1, 2, 3, 4, 5]
```

在这个例子中,我们可以看到,尽管`map`和`forEach`都可以对数组中的每个元素执行同样的操作(乘以2),但`map`返回了一个新的数组,原数组并没有改变;而`forEach`则没有返回值,我们需要创建一个新的数组来存储结果。同时,原数组在`forEach`操作后也没有发生改变。

2、解释下JavaScript中this是如何工作的?

在 JavaScript 中,`this`关键字是一个特殊的变量,它在每个函数作用域内都有定义。它的值取决于函数如何被调用。

1. **全局作用域或函数调用:** 在全局作用域或者普通函数调用中,`this`指向全局对象,也就是`window`(在浏览器中)或者`global`(在Node.js中)。

```javascript
console.log(this); // 输出:Window {...}

function test() {
  console.log(this);
}
test(); // 输出:Window {...}
```

2. **作为对象方法调用:** 当函数作为对象的一个方法被调用时,`this`指向这个对象。

```javascript
const obj = {
  name: 'Alice',
  sayHello: function() {
    console.log(this.name);
  }
};
obj.sayHello(); // 输出:Alice
```

3. **作为构造函数调用:** 当使用`new`关键字调用函数时,`this`指向新创建的对象。

```javascript
function Person(name) {
  this.name = name;
}

let alice = new Person('Alice');
console.log(alice.name); // 输出:Alice
```

4. **在事件处理函数中:** 在 DOM 事件处理函数中,`this`通常指向触发事件的元素。

```javascript
button.addEventListener('click', function() {
  console.log(this); // 输出:触发点击事件的button元素
});
```

5. **箭头函数:** 箭头函数没有自己的`this`,它会捕获其所在(即定义的位置)上下文的`this`值。

```javascript
const obj = {
  name: 'Alice',
  sayHello: function() {
    setTimeout(() => {
      console.log(this.name); // 输出:Alice
    }, 1000);
  }
};
obj.sayHello();
```

6. **使用call,apply,bind调用:** 使用`call`,`apply`或`bind`方法,可以设置函数运行时的`this`值。

```javascript
function greet() {
  console.log(`Hello, ${this.name}`);
}

const alice = { name: 'Alice' };
const bob = { name: 'Bob' };

greet.call(alice); // 输出:Hello, Alice
greet.call(bob); // 输出:Hello, Bob
```

总的来说,`this`的值是在函数被调用时确定的,而不是在函数被定义时确定。这就是 JavaScript 中的动态作用域。

3、JavaScript阻止事件冒泡的方法?

在JavaScript中,阻止事件冒泡可以使用事件对象的`stopPropagation`方法。当事件发生时,浏览器会创建一个事件对象,这个对象包含了与事件相关的各种信息和方法,其中就包括`stopPropagation`方法。

这个方法可以阻止当前事件继续向上层元素传播,也就是停止事件冒泡。

我们来看一个例子:

```javascript
document.querySelector("#child").addEventListener('click', function(event) {
  event.stopPropagation();
  console.log("Child element clicked!");
});

document.querySelector("#parent").addEventListener('click', function() {
  console.log("Parent element clicked!");
});
```

在这个例子中,当你点击ID为`child`的元素时,浏览器会首先执行该元素的点击事件处理函数,然后因为我们调用了`event.stopPropagation()`,事件就不会继续向上冒泡到父元素,也就是ID为`parent`的元素。所以,你只会看到控制台打印出"Child element clicked!",而不会看到"Parent element clicked!"。

需要注意的是,`stopPropagation`只能阻止事件向上冒泡,但不能阻止其他同级事件监听器的执行。如果你希望完全阻止事件的进一步传播,包括阻止其他同级事件监听器的执行,你可以使用`event.stopImmediatePropagation()`方法。

4、JavaScript阻止默认事件?

在JavaScript中,阻止默认事件可以使用事件对象的`preventDefault`方法。很多浏览器的事件都有默认的行为,例如点击链接会跳转到新的页面,提交表单会刷新页面等。如果我们不希望触发这些默认行为,就可以使用`preventDefault`方法。

下面是一个例子,展示了如何阻止链接的默认跳转行为:

```javascript
document.querySelector("a").addEventListener('click', function(event) {
  event.preventDefault();
  console.log("Link clicked, but default action is prevented.");
});
```

在这个例子中,当你点击链接时,浏览器会首先执行链接的点击事件处理函数。然后因为我们调用了`event.preventDefault()`,链接的默认跳转行为就被阻止了。所以,你会看到控制台打印出"Link clicked, but default action is prevented.",但页面并不会跳转到链接的目标地址。

需要注意的是,不是所有的事件都有默认行为,只有部分事件才有。对于没有默认行为的事件,调用`preventDefault`方法没有任何效果。另外,一些事件的默认行为无法被取消,例如页面的unload事件。对于这些事件,调用`preventDefault`方法也没有任何效果。

5、简述 Javascript 盒子模型?

在 Web 开发中,CSS 盒模型是用来布局和设计的基本概念。在 CSS 盒模型中,每个元素都被视为一个矩形的盒子,这个盒子具有宽度、高度、边距、填充和边框。

盒模型主要包含四个部分:

1. **内容(Content):** 这是盒子里面的实际内容,如文本、图片等。其尺寸可以通过 `width` 和 `height` 属性来设置。

2. **内边距(Padding):** 内边距是内容周围的空白区域,它清晰地隔离了内容和边框。内边距的大小可以通过 `padding` 属性来设置。

3. **边框(Border):** 边框就像是盒子的外壳,它包围了内容和内边距。边框的大小和样式可以通过 `border` 属性来设置。

4. **外边距(Margin):** 外边距是盒子和其他元素之间的空白区域。它在边框的外面,用来隔离盒子和其他元素。外边距的大小可以通过 `margin` 属性来设置。

在 CSS 中,盒模型有两种:标准盒模型和IE盒模型。

- **标准盒模型:** 在这个模型中,`width` 和 `height` 指的是内容区的宽度和高度,而不包括内边距、边框和外边距。总的盒子大小计算公式为:`总宽度 = width + padding-left + padding-right + border-left + border-right + margin-left + margin-right`,高度同理。

- **IE盒模型:** 在这个模型中,`width` 和 `height` 指的是内容区、内边距和边框的总宽度和高度。外边距不包括在内。总的盒子大小计算公式为:`总宽度 = width + margin-left + margin-right`,高度同理。

可以使用 CSS 的 `box-sizing` 属性来选择使用哪种盒模型,`content-box` 为标准盒模型,`border-box` 为IE盒模型。

6、Javascipt中async await 和promise和generator有什么区别?

`async/await`、`Promise` 和 `generator` 都是 JavaScript 中用于处理异步操作的工具,但它们的使用方式和机制各有不同。

**Promise:** Promise 是 JavaScript 中处理异步操作的一个对象。它有三种状态:pending(待定)、fulfilled(已成功)和 rejected(已失败)。Promise 在创建时处于 pending 状态,然后可能转换为 fulfilled 或 rejected 状态。一旦状态改变,就不能再次改变。Promise 可以使用 `then` 和 `catch` 方法来处理成功或失败的结果。

```javascript
let promise = new Promise((resolve, reject) => {
  // 异步操作
  if (/* 成功 */) {
    resolve(value);
  } else {
    reject(error);
  }
});

promise.then(value => {
  // 处理成功的结果
}).catch(error => {
  // 处理错误
});
```

**Generator:** Generator 是 ES6 引入的一种新的函数类型,它可以在执行过程中被暂停和恢复。Generator 使用 `yield` 关键字来暂停函数的执行,使用 `next` 方法来恢复执行。Generator 可以用于处理异步操作,但需要配合其他工具(如 Promise)使用。

```javascript
function* myGenerator() {
  const data = yield doAsyncOperation();
  console.log(data);
}

const generator = myGenerator();
generator.next().value.then(data => {
  generator.next(data);
});
```

**Async/Await:** Async/Await 是 ES7 引入的一种新的处理异步操作的方式,它是基于 Promise 的。Async/Await 使用 `async` 和 `await` 关键字,使得异步代码看起来像同步代码。这大大提高了代码的可读性和可维护性。

```javascript
async function myAsyncFunction() {
  try {
    const data = await doAsyncOperation();
    console.log(data);
  } catch (error) {
    // 处理错误
  }
}

myAsyncFunction();
```

总的来说,Promise 提供了一种在异步操作完成后处理结果的方式,Generator 提供了一种可以暂停和恢复的函数,而 Async/Await 则提供了一种更简洁、更直观的处理异步操作的方式。

 7、JavaScript中手写promise ?

在 JavaScript 中,Promise 是一个代表了异步操作最终完成或者失败的对象。我们可以手动创建一个 Promise,如下所示:

```javascript
function MyPromise(executor) {
  let self = this;
  self.status = 'pending'; // Promise 当前的状态
  self.value = undefined; // Promise 的值
  self.reason = undefined; // Promise 失败的原因

  // 成功
  function resolve(value) {
    if (self.status === 'pending') {
      self.status = 'fulfilled';
      self.value = value;
    }
  }

  // 失败
  function reject(reason) {
    if (self.status === 'pending') {
      self.status = 'rejected';
      self.reason = reason;
    }
  }

  try {
    executor(resolve, reject);
  } catch (error) {
    reject(error);
  }
}

MyPromise.prototype.then = function(onFulfilled, onRejected) {
  let self = this;
  if (self.status === 'fulfilled') {
    onFulfilled(self.value);
  }
  if (self.status === 'rejected') {
    onRejected(self.reason);
  }
}
```

这是一个最基础的 Promise 实现,它包含了 Promise 的基本逻辑。但是,这个实现还缺少很多真正的 Promise 具备的功能,比如链式调用、异步支持、错误处理、`catch` 方法、`Promise.all` 方法、`Promise.race` 方法等等。

在实际开发中,我们通常使用内置的 Promise 对象,因为它已经实现了完整的功能,并且经过了大量的测试和优化。

8、JavaScript中promise.all作用?

`Promise.all` 是 JavaScript 中的一个 Promise 方法,它接收一个 Promise 对象的数组作为参数,返回一个新的 Promise 对象。这个新的 Promise 对象只有在所有的 Promise 对象都成功地完成(fulfilled)时才会完成,如果有任何一个 Promise 对象失败(rejected)了,那么新的 Promise 对象会立即失败。

在所有的 Promise 对象都成功完成时,新的 Promise 对象的结果会是一个数组,这个数组包含了每个 Promise 对象的结果。这些结果的顺序和原来的 Promise 对象的顺序一致。

如果有任何一个 Promise 对象失败了,新的 Promise 对象的结果会是那个失败的 Promise 对象的结果。

下面是一个例子:

```javascript
let promise1 = Promise.resolve(3);
let promise2 = 42;
let promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then(values => {
  console.log(values); // 输出:[3, 42, "foo"]
});
```

在这个例子中,`Promise.all` 接收了三个 Promise 对象,当这三个 Promise 对象都成功完成时,它返回的 Promise 对象也成功完成,结果是一个包含了每个 Promise 对象结果的数组。

`Promise.all` 在处理多个相互独立的异步操作,并且需要等待所有异步操作都完成时非常有用。

9、Javascript 浅拷贝/深度拷贝的区别?

在 JavaScript 中,浅拷贝和深拷贝都是用来复制对象的,但它们复制的深度不同。

**浅拷贝(Shallow Copy):** 浅拷贝只复制对象的顶层属性。如果对象的属性值是基本类型(如数字、字符串、布尔值),那么就直接复制这个值;如果属性值是引用类型(如对象、数组),那么复制的是这个值的引用,而不是实际的对象或数组。这就意味着,如果你修改了新对象的一个引用类型的属性,那么原对象的对应属性也会被修改。

```javascript
let obj1 = { a: 1, b: [1, 2, 3] };
let obj2 = {...obj1};
obj2.b.push(4);
console.log(obj1.b); // 输出:[1, 2, 3, 4]
```

在这个例子中,我们使用了对象扩展运算符(...)来创建一个新的对象,这是一种浅拷贝的方式。当我们修改了新对象的 b 属性时,原对象的 b 属性也被修改了。

**深拷贝(Deep Copy):** 深拷贝不仅复制对象的顶层属性,还会递归地复制所有的子属性。无论属性值是基本类型还是引用类型,都会创建一个新的副本。这就意味着,新对象和原对象完全独立,修改其中一个不会影响另一个。

```javascript
let obj1 = { a: 1, b: [1, 2, 3] };
let obj2 = JSON.parse(JSON.stringify(obj1));
obj2.b.push(4);
console.log(obj1.b); // 输出:[1, 2, 3]
```

在这个例子中,我们使用了 `JSON.stringify` 和 `JSON.parse` 方法来创建一个新的对象,这是一种深拷贝的方式。当我们修改了新对象的 b 属性时,原对象的 b 属性没有被修改。

需要注意的是,使用 `JSON.stringify` 和 `JSON.parse` 方法进行深拷贝有一些限制,比如无法复制函数和循环引用的对象等。在实际开发中,我们通常会使用一些库(如 lodash)的深拷贝函数,因为这些函数已经处理了各种边缘情况。


 

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

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

相关文章

Ubuntu18.04 重装/升级 eigen 教程

目录 一、Eigen 1.1 ubuntu 查看 eigen 版本 1.2 卸载 老版本 eigen 二、安装 eigen 3.4.0 2.1 配置安装 2.2 查看版本 一、Eigen 1.1 ubuntu 查看 eigen 版本 $ dpkg -l | grep eigen1.2 卸载 老版本 eigen sudo updatedb locate eigen3会获得一堆输出,其…

springboot整合Kafka的快速使用教程

目录 一、引入Kafka的依赖 二、配置Kafka 三、创建主题 1、自动创建(不推荐) 2、手动动创建 四、生产者代码 五、消费者代码 六、常用的KafKa的命令 Kafka是一个高性能、分布式的消息发布-订阅系统,被广泛应用于大数据处理、实时日志分析等场景。Spring B…

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(二十一)- 微服务(1)

微服务 1.认识微服务 SpringCloud底层是依赖于SpringBoot的,并且有版本的兼容关系,如下: 2. 服务拆分 需求 : 把订单信息和用户信息一起返回 从订单模块向用户模块发起远程调用 , 把查到的结果一起返回 步骤 &…

多态(难的起飞)

注意 virtual关键字: 1、可以修饰原函数,为了完成虚函数的重写,满足多态的条件之一 2、可以菱形继承中,去完成虚继承,解决数据冗余和二义性 两个地方使用了同一个关键字,但是它们互相一点关系都没有 虚函…

JAVASE总结一

1、 2、引用也可以是成员变量(实例变量),也可以是局部变量;引用数据类型,引用, 我们是通过引用去访问JVM堆内存当中的java对象,引用保存了java对象的内存地址,指向了JVM堆内存当中…

ESP32 - Micropython ESP-IDF 双线教程 脉宽调制(PWM)(1)

ESP32 - Micropython ESP-IDF 双线教程 脉宽调制(PWM) PWM 的基本原理PWM 的应用PWM 的优点PWM 的实现方式ESP32-micropython 中的 PWM 功能使用 micropython 控制 PWM 的代码示例代码介绍 ESP32-IDF 中的 PWM 功能1. 初始化配置函数2. 引脚绑定函数3. 占…

常见算法200个(5):快速排序(快排)

JS实现快速排序 1.快速排序思路: 选择数组中的一个值作为基准,将数组中小于该值的数置于该数之前,大于该值的数置于该数之后,接着对该数前后的两个数组进行重复操作直至排序完成。 2.代码实现: function quick(arr)…

使用 Snort 进行入侵检测

使用 Snort 进行入侵检测 Snort 是一种流行的开源入侵检测系统。您可以在http://www.snort.org/上获取它。Snort 分析流量并尝试检测和记录可疑活动。Snort 还能够根据其所做的分析发送警报。 Snort 安装 在本课中,我们将从源代码安装。此外,我们不会安…

2024 前端面试每日1小时

三日 1. 如何理解Vue的模板编译原理 Vue的模板编译实际就是将模板字符串通过解析、优化和代码生成等步骤转换为渲染函数的过程。这个过程中,AST扮演了非常重要的角色,它用树形结构描述了模板的内容和结构,是编译过程的核心数据结构&#xff…

MySQL——适合不适合创建索引的情况

那些情况适合创建索引 1、字段的数值具有唯一性的限制 索引本身可以起到约束的作用,比如唯一索引、主键索引都是可以起到唯一性约束的,因此在我们的数据表中,如果某个字段是唯一性的,就可以直接创建唯一性索引,或者主…

Nodejs 爬虫 案例

1.安装: npm install cheerio npm install axios2.介绍: 2.1 cheerio 特点和用途描述: HTML解析和操作:Cheerio 可以将 HTML 字符串加载到内存中,并将其转换为一个可操作的 DOM 树结构,从而可以方便地对…

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

从各个域控制器硬件解决方案来看,MPU可能来自多个供应商,有瑞萨,有NXP等,但对于MCU来说,基本都采用英飞凌TC3xx。 今天我们就来看一下TC3xx的启动过程,主要包含如下内容: uC上电过程中,会经过一个上电时序,从复位状态“脱离”出来;Boot Firmware是复位后第一个执行的…

使用 Effect 同步-09

有些组件需要与外部系统同步。例如,你可能希望根据 React state 控制非 React 组件、设置服务器连接或在组件出现在屏幕上时发送分析日志。Effects 会在渲染后运行一些代码,以便可以将组件与 React 之外的某些系统同步。 简单理解,就是需要操…

Python实现对Word文档内容出现“重复标题”进行自动去重(4)

前言 本文是该专栏的第4篇,后面会持续分享Python办公自动化干货知识,记得关注。 在本专栏上一篇文章《Python实现对Word文档内容出现“重复标题”进行自动去重(3)》中,笔者有详细介绍使用python对word文档内容的目标文本进行自动去重。只不过本文要介绍的“去重方法”与上…

计算机专业必考之计算机指令设计格式

计算机指令设计格式 例题: 1.设相对寻址的转移指令占3个字节,第一字节为操作码,第二,第三字节为相对偏移量, 数据在存储器以低地址为字地址的存放方式。 每当CPU从存储器取出一个字节时候,自动完成&…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-24.1,2 SPI驱动实验-SPI协议介绍

前言: 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM(MX6U)裸机篇”视频的学习笔记,在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

计算机组成原理易混淆知识点总结(持续更新)

目录 1.机器字长,存储字长与指令字长 2.指令周期,机器周期,时钟周期 3.CPI,IPS,MIPS 4.翻译程序和汇编程序 5.计算机体系结构和计算机组成的区别和联系 6.基准程序执行得越快说明机器的性能越好吗? 1.机器字长,存储字长与指令字长 不同的机器三者…

AI智能体|扣子Coze文生图功能接入微信公众号

大家好,我是无界生长。 AI智能体|扣子Coze文生图功能接入微信公众号本文分享了如何将Coze平台的文生图功能接入微信公众号的详细操作流程,包括创建图像流、创建并配置Bot、设置提示词和开场白、调试、发布等步骤。如果看完还没学会的话&…

网页图片加载慢的求解指南

网页/图片加载慢的求解指南 一、前言与问题描述 今天刚换上华为的HUAWEI AX3 Pro New,连上WIFI后测速虽然比平时慢,但是也不算太离谱,如下图所示: 估计读者们有也和作者一样,还没意识到事情的严重性😁。 …

08Django项目--用户管理系统--查(前后端)

对应视频链接点击直达 TOC 一些朋友加我Q反馈,希望有每个阶段的完整项目代码,那从今天开始,我会上传完整的项目代码。 用户管理,简而言之就是用户的增删改查。 08项目点击下载,可直接运行(含数据库&…