前端面试笔试(三)

目录

一、数据结构算法等综合篇

二、代码输出篇

1.yield与生成器函数

2.this指向有关

[3.instanceof 与Array.isArray](#3.instanceof 与Array.isArray)

[4.继承class cls extends Array,调用里面的sum方法](#4.继承class cls extends Array,调用里面的sum方法)

三、css、html、JavaScript篇

1.哪项不能提高dom元素操作效率?

2.contenteditable

基本功能:

使用场景:

注意:

示例:

3.关于promise的then、catch、resolve、reject

逐项解析:


一、数据结构算法等综合篇

二、代码输出篇

1.yield与生成器函数

javascript 复制代码
  function* func(){
      yield 117;
      yield 935;
      return 130;
  }
  const res=func();
  for(let item of res){
      console.log(item);
  }

输出结果为:

这段代码定义了一个生成器函数 func,并通过 for...of 循环遍历了该生成器函数返回的迭代器 res

  • function* func(){...} 定义了一个名为 func 的生成器函数。生成器函数是一种特殊的函数,可以暂停执行并在之后重新恢复执行,通过 yield 关键字实现。
  • yield 117;:当生成器函数被调用并迭代时,它会在这里暂停,并返回 117 给迭代器。
  • yield 935;:在下一次迭代时,函数会从这里继续执行,并返回 935。
  • return 130;:当生成器函数完成迭代(即没有更多的 yield 表达式可供迭代),它可以通过 return 语句返回一个值。这个值可以通过调用迭代器的 return() 方法获取,但在这个例子中并没有这样做。
  • const res = func();:调用生成器函数 func,并将返回的迭代器赋值给变量 res
  • for(let item of res){...}:使用 for...of 循环遍历迭代器 res。每次迭代,迭代器会执行生成器函数的下一个 yield 表达式,直到没有更多的 yield 表达式。
  • console.log(item);:在循环体内,打印出每次迭代得到的值。

如果要获取这个返回的130,需要:

javascript 复制代码
console.log(res.return().value)

2.this指向有关

javascript 复制代码
  function test(){
      this.flag=false;
      this.change=()=>{
          this.flag=true;
          console.log(button.flag);
      };
  }
  const button=new test()
  document.addEventListener("click",button.change)

点击了浏览器后输出为true

  • 首先button是通过new test()的方式来得到的,new返回的对象,this指向对象本身 。所以此时button.flag = false;
  • button.change 是一个箭头函数 而不是普通的函数,所以他的this要取所在词法作用域的this ,因为在test函数中,所以changethis就是testthis
  • 我觉得 作用域可以分为函数作用域全局作用域(虽然还有块级作用域,但是在这可以不考虑)
  • 当点击document的时候触发函数执行。因为change的this是testthis也就是button,所以这里将buttonflag改为了true。所以最后打印的就是true
  • 如果这里的函数并不是箭头函数,而是普通的函数,那么这里的this就会变成document。此时打印document.flag 得到的就是true;(谁调用this指向谁),而程序的输出结果就会变成false

3.instanceof 与Array.isArray

javascript 复制代码
  var iframe=document.createElement('iframe');
  document.documentElement.appendChild(iframe);
  iframe.src="javascript:var a=[];"
  var a,b;
  setTimeout(()=>{
      a=iframe.contentWindow.a;
      b=[];
      console.log(a instanceof Array,b instanceof Array);
      console.log(Array.isArray(a),Array.isArray(b));

  })

输出为:

false true

true true

上面代码创建了一个 iframe 元素,并将其附加到了文档的根元素(通常是 html 元素)上。然后,您尝试通过设置 iframe.src 为一个 javascript: URL 来在 iframe 中执行一些 JavaScript 代码。

在 iframe 中声明的变量 a 是局部的,它不会影响到外部页面的变量作用域。

  • iframe.contentWindow.a 即使是一个数组(在假设的情况下),它也是一个不同上下文(即 iframe 的全局作用域)中的数组实例,因此 a instanceof Array 在外部上下文中会返回 false
  • b 是在外部上下文中声明的数组,所以 b instanceof Array 会返回 true
  • Array.isArray() 方法不受上下文限制,它会正确地识别任何数组,因此 Array.isArray(a)Array.isArray(b) 都会返回 true(再次强调,这是在假设 iframe.contentWindow.a 实际上是一个数组的情况下)。

4.继承class cls extends Array,调用里面的sum方法

javascript 复制代码
  class cls extends Array{
      sum(){
          return this.reduce(function reducer(acc,curr){
              return acc+curr;
          },0);
      }
  }
  const x=new cls(3);
  const y=new Array(3);
  const z=cls.of(3);
  console.log(x.length,y.length,z.length);//3 3 1
  console.log(x.sum())//0
  console.log(y.sum)//undefined
  console.log(z.sum())//3
  1. x 是使用 new cls(3) 创建的实例。这里需要注意的是,当向 Array 或其子类构造函数传递一个单独的数字参数时,它会创建一个具有该长度(但元素未定义)的数组。因此,x 是一个长度为 3 的数组,但其所有元素都是 undefined

  2. y 是使用 new Array(3) 创建的普通数组实例,与 x 类似,它也是一个长度为 3、元素未定义的数组。

  3. z 是使用 cls.of(3) 创建的实例。Array.of 方法创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。因此,z 是一个包含一个元素(数字 3)的数组。

由于 x 是一个长度为 3 的数组,但其所有元素都是 undefinedundefined 在数学运算中被视为 NaN(Not-a-Number)。当使用 reduce 方法对包含 NaN 的数组进行求和时,结果也将是 NaN。但是,由于 NaN + 0 在这个特定的上下文中(即初始累加器值为 0,且数组元素为 undefined)实际上会导致累加器保持为 0(因为 undefined 转换为数字时是 NaN,但 NaN 在加法中的行为是特殊的,它不会改变一个有效的数字值),所以最终结果是 0。

y 是一个普通的 Array 实例,它并没有 sum 方法。因此,输出是 undefined

z 是一个包含单个元素 3 的数组。调用 z.sum() 会使用 reduce 方法计算数组中元素的和,因此结果是 3。


三、css、html、JavaScript篇

1.哪项不能提高dom元素操作效率?

A.用DocumentFragment替代多次appendChild操作

B.插入大量DOM元素时用innerHTML替代逐个构建元素

C.处理列表子元素点击事件时,使用事件代理

D.使用addEventListener替代onxxx(如onClick)进行事件绑定

逐项解析:

A。使用 DocumentFragment 可以在内存中构建一个文档片段,然后将这个片段一次性添加到 DOM 树中。这样做的好处是减少了多次的 DOM 重绘和重排,因此可以显著提高性能。

B。使用 innerHTML 可以一次性地设置元素的内部 HTML 内容,这通常比逐个创建和添加 DOM 元素要快得多,因为浏览器在内部进行了优化。

C。事件代理是一种技术,它允许你将事件监听器添加到父元素上,而不是每个子元素上。通过检查事件的目标元素,可以确定哪个子元素触发了事件。这样可以减少事件监听器的数量,从而提高性能。

D。

  • addEventListener 提供了更灵活的事件处理机制,允许你为同一个元素添加多个事件监听器而不会覆盖之前的监听器。此外,它支持更细粒度的事件控制(如捕获和冒泡阶段)。
  • 然而,就单次事件绑定操作的性能而言,addEventListeneronxxx(如 onClick)之间的性能差异通常很小,并且不一定直接导致DOM操作的整体效率提升。这个选项主要是关于事件管理的灵活性和兼容性,而不是直接提升DOM操作的效率。

2.contenteditable

contenteditable 是 HTML5 中的一个全局属性,它允许用户编辑元素中的内容。

基本功能:

  • contenteditable 属性可以被添加到 HTML 元素中,如 divtablepspanbody 等,使这些元素变得可编辑。
  • contenteditable 属性被设置为 true 时,该元素就可以被用户编辑。
  • contenteditable 属性被设置为 false 时,该元素不能被用户编辑,这是该属性的默认值(当属性值缺失时,效果与设置为 false 相同)。
  • contenteditable 属性还可以被设置为 inherit,此时该元素会继承其父元素的 contenteditable 状态。

使用场景:

  • 编辑器功能contenteditable 属性最常用的场景是在网页上创建一个可编辑的文本区域,使用户能够直接在网页上输入和编辑文本内容,类似于常见的文本编辑器功能。
  • 富文本编辑contenteditable 属性还可以用于创建富文本编辑器,允许用户在文本中添加格式、图片、链接等样式和元素。
  • 评论功能 :网站或应用的评论框通常会使用 contenteditable 属性,使用户能够直接在评论框中输入评论内容,并实时提交到服务器。
  • 笔记应用contenteditable 属性也适用于笔记应用或在线日记,用户可以直接在网页上输入和保存个人的笔记或日记内容。
  • 在线表单 :有些情况下,内容需要在表单中进行编辑,此时 contenteditable 属性可以用于在表单中添加富文本内容,如说明文字或公告等。

注意:

  • 设置了 contenteditable 属性的元素必须是可以获得鼠标焦点的元素,并且在点击鼠标后要向用户提供一个插入符号,提示可编辑。
  • 在使用 contenteditable 属性时,需要注意如何保存用户编辑的内容。通常可以通过监听失焦事件(如 blur 事件)来获取并保存用户编辑后的内容。

示例:

html 复制代码
<!DOCTYPE html>
<html>
<body>
<p contenteditable="true">这是一个可以编辑的段落。</p>
</body>
</html>

在这个示例中,<p> 元素被添加了 contenteditable="true" 属性,因此它变得可编辑。用户可以直接在网页上修改这个段落的内容。


3.关于promise的then、catch、resolve、reject

下面关于Promise说法错误的是:

A.调用then或catch方法都是异步进行的,但是执行速度比较快

B.Promise.resolve(value),Promise.reject(reason)是Promise构造器上直接提供的一组静态方法

C.resolve()和reject()都是直接生成一个进入响应状态的promise对象,其参数就是进入相应状态时传递过去的参数,可以在完成回调的参数中得到

D.Promise构造器的prototype上还有两个方法,分别是then和catch,这两个方法的参数也是回调函数,这些函数会在Promise实例进入不同状态后被调用

逐项解析:

先说错误的C,resolve()reject() 并不是直接生成Promise对象的函数,而是Promise构造函数执行时传递给executor(执行器)函数的两个参数。这两个参数是函数,用于在异步操作成功或失败时分别改变Promise的状态,并传递相应的结果值或原因。

异步操作成功时,调用resolve函数,使Promise对象的状态变为fulfilled(已完成),将结果值传递给后续通过then方法注册的回调函数。

异步操作失败时,调用reject函数,使Promise对象的状态变为rejected(已拒绝),将失败原因传递给后续通过catch方法或then方法的第二个回调函数注册的错误处理函数。

因此:resolve()和reject()并不是直接生成Promise对象的函数,而是用于改变Promise对象状态的函数,它们是Promise构造器上直接提供的一组静态方法。

A:then和catch方法都是异步微任务,会在当前栈清空后立即执行,但是执行速度相对较快,因为它们只是将回调函数添加到Promise的回调队列中,等待Promise状态改变时执行。

B:见C项解析

D:Promise构造器的prototype上的then和catch方法用于注册回调函数,会在Promise实例进入不同状态(fulfilled或rejected)后被调用。then接收两个回调函数作为参数,第一个用于处理fulfilled状态,第二个(可选的)用于处理rejected状态。catch接收一个回调函数作为参数,用于处理reject状态。


加油加油^_^

相关推荐
m0_7482361111 分钟前
Calcite Web 项目常见问题解决方案
开发语言·前端·rust
Watermelo61724 分钟前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
m0_7482489425 分钟前
HTML5系列(11)-- Web 无障碍开发指南
前端·html·html5
m0_7482356137 分钟前
从零开始学前端之HTML(三)
前端·html
一个处女座的程序猿O(∩_∩)O3 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
hackeroink6 小时前
【2024版】最新推荐好用的XSS漏洞扫描利用工具_xss扫描工具
前端·xss
LCG元7 小时前
【面试问题】JIT 是什么?和 JVM 什么关系?
面试·职场和发展
迷雾漫步者7 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-8 小时前
验证码机制
前端·后端
燃先生._.9 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js