前端面试题

简介: dasdada

基础类问题

h5的新特性

html5

备注

只有一种 DOCTYPE ⽂件类型声明(统 一标准)

<!DOCTYPE html>

增加了一些新的标签元素(功能, 语义化)

section, video, progress, nav, meter, time, aside, canvas, command, datalist, details, embed, figcaption, figure, footer, header, hgroup...

input 支持了几个新的类型值

date, email, url 等等

新增了一些标签属性

charset(⽤于 meta 标签);async(⽤于 script 标 签)

新增的全域属性

contenteditable, draggable... hidden...

新增API

本地存储, 地理定位, Canvas绘图, 拖拽API, 即时通信 WebSocket

css3新增的特性

说出下方常用的即可, 无需全部背出

  1. 伪元素
  2. 弹性布局flex
  3. 媒体查询
  4. 圆角
  5. 渐变
  6. 阴影
  7. 平面转换
  8. 3D转换
  9. 动画

盒子/图片水平垂直居中:

  • 要使一个盒子水平和垂直居中,最简单的方法是使用 CSS 的 flex 布局。

首先,让父元素使用 display: flex 并设置 align-items: centerjustify-content: center,这样父元素就会在水平和垂直方向上居中。然后,将子元素设置为盒子即可。

下面是一个示例:

.parent {
  display: flex;
  align-items: center;
  justify-content: center;
}
.child {
  width: 100px;
  height: 100px;
}
<div class="parent">
  <div class="child">I am centered</div>
</div>

如果你希望盒子在垂直方向上居中,但在水平方向上靠左或靠右,则可以使用 justify-content: flex-startjustify-content: flex-end

如果你想使用其他布局方式来实现居中,也可以使用 position: absolute 和 transform: translate(-50%, -50%)。

.parent {
  position: relative;
}
.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

还有其他一些方法可以实现居中,但上述方法是最常用的。

css盒模型:

CSS盒模型是用于描述HTML元素的布局的一种方法。它用于在浏览器中渲染HTML元素的边框和内容。

每个HTML元素都是一个盒子,其中包含元素的内容,内边距(padding),边框和外边距(margin)。

在CSS中,你可以使用多种属性来控制盒模型的外观和布局,包括:

  • widthheight属性用于控制元素的内容区域的大小。
  • padding属性用于控制元素的内边距。
  • border属性用于控制元素的边框。
  • margin属性用于控制元素的外边距。

你还可以使用box-sizing属性来控制元素的盒模型类型。默认情况下,HTML元素使用的是“标准盒模型”,在这种情况下,元素的宽度和高度仅指内容区域的宽度和高度。但是,你也可以将box-sizing属性设置为“边距盒模型”,在这种情况下,元素的宽度和高度将包括内边距和边框。

块级元素和行内元素:

在HTML中,元素可以分为两种类型:块级元素和行内元素。

块级元素:

  • 块级元素在文档流中占据一整行。
  • 块级元素可以设置宽度和高度。
  • 块级元素可以设置内外边距和边框。

常见的块级元素包括:divh1pformheaderfootersection等。

行内元素:

  • 行内元素在文档流中只占据所需的空间。
  • 行内元素不能设置宽度和高度。
  • 行内元素只能设置内边距。

常见的行内元素包括:aspanbuttoninputlabelselect等。

注意:元素的类型并不是固定的,你可以使用CSS的display属性来改变元素的类型。例如,你可以将一个行内元素转换为块级元素,或者将一个块级元素转换为行内元素。

css选择器权重值:

在CSS中,选择器的权重值(也称为优先级)是用于确定哪些样式规则应该应用到HTML元素的一种机制。

选择器的权重值由两部分组成:选择器的特殊性和样式定义的位置。

选择器的特殊性是根据选择器中使用的各种类型的选择器来计算的。每种类型的选择器都有一个固定的权重值,如下表所示:

选择器类型

权重值

通配符(*

0

元素选择器(例如p

1

类选择器(例如.class

10

ID选择器(例如#id

100

属性选择器(例如[type]

10

伪类选择器(例如:hover

10

伪元素选择器(例如::before

10

为了计算选择器的特殊性,需要对选择器中使用的每种类型的选择器的权重值进行加权。例如,如果选择器为#id .class p,则其特殊性为(100 * 1) + (10 * 1) + (1 * 1) = 111

样式定义的位置也会影响选择器的权重值。在所有其他因素相同的

的情况下,样式定义出现的位置越靠后,其权重值就越大。这意味着如果有多个样式规则适用于同一个HTML元素,那么最后出现的样式规则会覆盖先前出现的样式规则。

为了确定哪些样式规则应用到HTML元素,浏览器会比较所有适用于该元素的样式规则的权重值,并应用权重值最大的样式规则。

你可以使用!important来强制应用样式规则,即使其权重值低于其他样式规则。例如,如果你想要强制应用某个样式规则,你可以在样式值后面添加!important,例如:

p {
  color: red !important;
}

这将强制将所有段落的文本颜色设置为红色,即使有其他样式规则为段落设置了不同的颜色。注意,使用!important会使样式规则的权重值变得非常高,因此应该谨慎使用。

H5事件:

  • onblur失焦事件
  • onfocus聚焦事件
  • onchange改变事件
  • onclick点击事件
  • onerror错误事件
  • oninput输入事件
  • onkeydown键盘按下事件
  • onkeyup键盘抬起事件
  • onmousemove鼠标移动事件
  • onmouseover鼠标进入事件
  • onmouseout鼠标移出事件等

H5中input元素的type属性值:

  • color颜色
  • password密码
  • text文本
  • CheckBox复选框
  • radio单选框
  • date日期
  • button按钮
  • submit提交按钮等


基础相关

js数据类型

JavaScript有七种数据类型:

  1. 字符串(String):用于表示文本数据。例如:"hello world"。
  2. 数字(Number):用于表示数值数据。例如:42。
  3. 布尔(Boolean):用于表示真假值。例如:true或false。
  4. undefined:用于表示未定义的值。
  5. null:用于表示空值。
  6. 对象(Object):用于表示各种类型的数据的集合。例如:{name: "John", age: 30}。
  7. 数组(Array):用于表示一组有序的值的集合。例如:[1, 2, 3]。

JavaScript还有一种数据类型叫做函数(Function),它是一个可执行的代码块,可以被当作数据来使用。

你可以使用typeof运算符来检查一个变量的数据类型。例如:

let num = 42;
console.log(typeof num); // "number"
let str = "hello world";
console.log(typeof str); // "string"
let bool = true;
console.log(typeof bool); // "boolean"
let obj = {name: "John", age: 30};
console.log(typeof obj); // "object"
let arr = [1, 2, 3];
console.log(typeof arr); // "object"
let func = function() {};
console.log(typeof func); // "function"
let undef;
console.log(typeof undef); // "undefined"
let nul = null;
console.log(typeof nul); // "object"

注意,使用typeof运算符检查数组和null的数据类型时会返回"object"。因此,如果你想要确定一个变量是否是数组或null,你可以使用其他方法,例如使用Array.isArray()方法来检查一个变量是否是数组,或者使用双等号(==)进行比较来检查一个变量是否是null。例如:

let arr = [1, 2, 3];
console.log(Array.isArray(arr)); // true
let nul = null;
console.log(nul == null); // true

此外,JavaScript还有一种特殊的数据类型叫做符号(Symbol),它用于创建唯一的值。你可以使用Symbol()函数来创建一个符号,例如:

let sym = Symbol();
console.log(typeof sym); // "symbol"

符号是JavaScript的一种新的数据类型,可以用来创建唯一的标识符,例如在对象的属性名称中使用。因为符号是唯一的,所以你可以使用它来防止属性名称冲突。例如:

let sym1 = Symbol();
let sym2 = Symbol();
let obj = {
  [sym1]: "hello",
  [sym2]: "world"
};
console.log(obj[sym1]); // "hello"
console.log(obj[sym2]); // "world"

注意,使用符号作为对象属性名称时,需要在属性名称前后添加方括号,这样才能正确地将属性名称解析为符号。

11、回流和重绘

回流(reflow)是指当浏览器渲染HTML页面时,对页面布局和几何的计算过程。当页面中的元素的大小、位置或布局方式改变时,浏览器就需要进行回流来调整布局。

重绘(repaint)是指当浏览器渲染HTML页面时,对页面中元素的外观进行更新的过程。当页面中元素的颜色、字体或其他外观属性改变时,浏览器就需要进行重绘来更新外观。

回流和重绘都是浏览器在渲染HTML页面时执行的必要过程,但是它们都有一定的开销,因此应该尽量避免不必要的回流和重绘。例如,你可以使用优化的CSS选择器和结构来减少回流的次数,或者使用缓存来避免重复的重绘。

注意,在JavaScript中有一些操作会触发回流和重绘

,例如:

  • 改变HTML元素的尺寸或位置,例如使用offsetWidth、offsetHeight、offsetLeft、offsetTop等属性。
  • 改变HTML元素的布局方式,例如使用display、position、float等属性。
  • 改变HTML元素的外观,例如使用color、background-color、font-size等属性。

你可以使用浏览器的开发工具来查看页面的回流和重绘次数,以及每次回流和重绘的原因。这有助于你发现并优化页面的性能问题。

此外,你还可以使用requestAnimationFrame()函数来让浏览器在下一次重绘之前执行特定的代码。这可以让你在更新页面元素的外观时,将多个操作合并成一次重绘,从而减少重绘的次数。例如:

function updatePage() {
  // 更新页面元素的外观
  requestAnimationFrame(updatePage);
}
updatePage();

注意,requestAnimationFrame()函数是异步执行的,因此你不能依赖它来控制代码的执行顺序。

12、闭包

闭包是一种特殊的对象,它包含了一个函数和与该函数相关的引用环境。

闭包的函数可以访问闭包创建时的环境,即使在该函数被调用时,外部的环境已经发生了变化。这使得闭包很适合用来做回调函数或者保存状态。

举个例子,假设你有一个函数,它接受一个数字作为参数,并返回一个函数。该返回的函数可以对传入的数字进行累加,每次调用都会将累加器加 1:

在上面的例子中,createAdder 函数创建了一个闭包,该闭包包含了一个函数和与该函数相关的环境。这个环境包含了变量 x 的值。当我们调用 createAdder(5) 时,它返回了一个新函数,这个函数可以对传入的参数 y 进行累加。在这个函数中,变量 x 的值是 5,所以调用 add5(2)add5(10) 时,都会将它们的参数与 5 相加。

闭包是一种非常有用的技术,它可以帮助你保存状态、创建封装的函数等


13、原型和原型链

在JavaScript中,每个对象都有一个原型(prototype),它是另一个对象。原型对象可以包含属性和方法,这些属性和方法可以被对象继承。这种继承机制被称为原型链(prototype chain)。

例如,你可以定义一个Person构造函数来表示人,并在Person.prototype中定义sayHello方法,表示人会说话:

function Person(name) {
  this.name = name;
}
Person.prototype.sayHello = function() {
  console.log(`Hello, my name is ${this.name}`);
};
let john = new Person("John");
john.sayHello(); // "Hello, my name is John"

在上面的例子中,john是Person类型的对象,它继承了Person.prototype中的sayHello方法。你可以使用instanceof运算符来检查一个对象是否是某个类型的实例,例如:

console.log(john instanceof Person); // true

注意,每个对象都有一个constructor属性,表示该对象的构造函数。你可以使用constructor属性来检查一个对象的类型,例如:

console.log(john.constructor === Person); // true

此外,每个对象还有一个__proto__属性,表示该对象的原型。你可以使用__proto__属性来检查一个对象的原型对象,例如:

console.log(john.__proto__ === Person.prototype); // true


14、this指向问题

在 JavaScript 中,this 关键字的指向可能有以下几种情况:

  1. 在全局作用域中,this 指向全局对象。在浏览器中,全局对象是 window,在 Node.js 中,全局对象是 global
  2. 在函数中,默认情况下,this 指向全局对象。但是,如果将函数作为对象的方法调用,则 this 指向调用方法的对象。
  3. 在箭头函数中,this 的指向是定义时所在的作用域的 this。箭头函数没有自己的 this,因此它永远不会改变指向。
  4. 可以使用 callapplybind 方法显式地指定 this 的指向。

例如:

const obj = {
  name: 'John',
  greet: function() {
    console.log(`Hello, ${this.name}!`);
  }
};
obj.greet();  // Hello, John! 因为是obj调用的greet方法,所以greet方法内部的this指向的是obj
const greet = obj.greet;
greet();  // Hello, undefined!,因为greet()是通过window调用的,所以this指向window
const arrowGreet = () => {
  console.log(`Hello, ${this.name}!`);
};
arrowGreet();  // Hello, undefined! this指向window
const boundGreet = obj.greet.bind(obj);
boundGreet();  // Hello, John!  // this被bind修改为了obj,所以this指向了obj


15、数组中forEach和map:

forEach 和 map 是 JavaScript 中常用的数组方法,都可以用来遍历数组中的元素,但是它们之间有一些区别:

  1. 功能不同:forEach 方法是遍历数组的方法,它提供了一种快捷的方式来遍历数组的所有元素。而 map 方法是映射数组的方法,它可以根据指定的规则对数组的每个元素进行映射,并返回一个新的数组。
  2. 返回值不同:forEach 方法不会返回任何值,只会对数组的每个元素执行回调函数。而 map 方法会返回一个新的数组,该数组的元素是对原数组中每个元素执行回调函数之后的返回值。
  3. 处理流程不同:forEach 方法是按顺序依次对数组的每个元素执行回调函数。而 map 方法是同时对数组的每个元素执行回调函数,并将结果放入新的数组中。

总的来说,forEach 和 map 是两种常用的数组方法,但是它们的功能、返回值和处理流程都有所不同。根据自己的需要,可以选择适合自己的方法进行使用。


16、 call、bind、apply ( 函数上下文调用模式 )

JavaScript 提供了三种方法来改变函数的调用上下文:callbindapply

call 方法允许您将函数的调用上下文指定为某个对象,并传递一些参数给函数。这样可以在不同的上下文中调用同一函数。例如:

function greet(greeting) {
  return `${greeting}, ${this.name}!`;
}
const person = { name: 'John' };
console.log(greet.call(person, 'Hello')); // "Hello, John!"

在上面的示例中,我们将函数 greet 的调用上下文指定为 person 对象,并传递了一个参数 'Hello'。这样,函数中的 this 将指向 person 对象,并返回 "Hello, John!"。

bind 方法与 call 类似,但它并不立即调用函数,而是返回一个新函数,该函数的调用上下文已被指定为您提供的对象。例如:

const greetJohn = greet.bind(person);
console.log(greetJohn('Hello')); // "Hello, John!"

在上面的示例中,我们使用 bind 方法将函数 greet 的调用上下文指定为 person 对象,并返回了一个新函数 greetJohn。当我们调用 greetJohn 时,它的调用上下文已被指定为 person,并返回 "Hello, John!"。

apply 方法与 call 类似,但它允许您使用数组来传递参数,而不是使用单独的参数列表

另外,还有几点需要注意:

  • 在使用 callapply 时,您必须立即调用函数,而 bind 方法则返回一个新函数。
  • 在使用 bind 方法时,您可以通过在绑定时提供额外的参数来为新函数指定参数。例如:
const greetJohnHello = greet.bind(person, 'Hello');
console.log(greetJohnHello()); // "Hello, John!"

在这种情况下,新函数 greetJohnHello 将固定使用参数 'Hello',无论您在调用时提供了什么参数。

17、new操作符具体过程

使用 new 操作符创建一个新对象的过程如下:

  1. 创建一个新对象。
  2. 将这个新对象的原型设置为构造函数的原型。
  3. 将这个新对象的 this 设置为这个新对象。
  4. 如果构造函数返回了对象,则返回这个对象;否则,返回这个新对象。

例如,下面是使用 new 操作符创建一个新对象的示例:

function Person(name) {
  this.name = name;
}
Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}`);
};
const john = new Person('John');
john.greet(); // "Hello, my name is John"

在这个例子中,我们定义了一个构造函数 Person,然后使用 new 操作符创建了一个新的 Person 对象,并将其赋值给变量 john。这个新对象继承了 Person.prototype 上的属性和方法,并且其 this 被设置为这个新对象。

注意,使用 new 操作符创建对象时,构造函数中的代码会在新对象上执行,并且新对象会继承构造函数的原型。因此,在上面的示例中,新对象 john 具有名为 name 的属性,并且可以调用 Person.prototype 上的 greet 方法。

在使用 new 操作符时,还有几点需要注意:

  • 如果构造函数返回了对象,则返回这个对象,而不是这个新对象。这意味着,如果构造函数中的代码显式地返回了一个对象,则这个对象将作为最终结果返回,而新创建的对象将被忽略。例如:
function Person(name) {
  this.name = name;
  return { greeting: 'Hello' };
}
const john = new Person('John');
console.log(john); // { greeting: 'Hello' }

在这个例子中,构造函数返回了一个对象,因此最终结果是这个对象,而不是新创建的对象。

  • 如果构造函数返回了原始值(例如数字、字符串或布尔值),则忽略该值并返回新对象。例如:
function Person(name) {
  this.name = name;
  return 42;
}
const john = new Person('John');
console.log(john); // Person { name: 'John' }

在这个例子中,构造函数返回了数字 42,但最终结果仍然是新创建的对象。

  • 如果构造函数没有返回值,则默认返回新对象。例如:
function Person(name) {
  this.name = name;
}
const john = new Person('John');
console.log(john); // Person { name: 'John' }

在这个例子中,构造函数没有返回值,因此最终结果是新创建的对象。

总之,new 操作符创建一个新对象并使用构造函数初始化它。它还会将新对象的原型设置为构造函数的原型,并且在构造函数执行时将 this 设置为新对象。如果构造函数返回了对象,则返回这个对象;否则,返回新对象。

使用 new 操作符是 JavaScript 中常见的模式,可以使用它来创建具有共同属性和方法的对象,并使用构造函数的原型链来为这些对象提供共享的功能。

18、浅拷贝和深拷贝

深拷贝和浅拷贝是指在复制对象时,复制的方式不同。

浅拷贝只是复制对象的引用,并不会复制对象本身。如果对象是基本类型,则复制的是值本身;如果对象是引用类型,则复制的是指向对象内存地址的指针。因此,如果对象是引用类型,则拷贝后的对象和原对象指向的是同一块内存,任意一方的修改都会影响另一方。

深拷贝则是完全复制了对象本身,包括对象内部的所有属性和方法。深拷贝后的对象和原对象没有任何关联,对其中一方的修改不会影响另一方。

在 JavaScript 中,可以使用以下方法实现深拷贝:

  1. 使用 JSON 序列化和反序列化。这种方法适用于简单对象和数组,但不能复制函数、正则表达式、日期等对象。

使用递归算法。这种方法可以复制任意类型的对象

另外,JavaScript 中还有一种浅拷贝的方法:使用 Object.assign() 函数。这个函数可以把一个或多个源对象的所有可枚举属性复制到目标对象中。

这种方法只能复制对象的属性,对于对象的方法和属性值为对象的属性,不会进行复制。


19、js事件循环:

JavaScript 是一种单线程语言,这意味着只能执行一个任务。但是,JavaScript 引擎会在后台持续执行一些任务,例如响应用户的输入、下载网络资源等。这些任务是由事件循环管理的。

事件循环是一种机制,用于在执行主线程的同时处理异步任务。它按照以下步骤工作:

  1. 主线程执行同步任务。
  2. 当遇到异步任务时,将其排入队列中。
  3. 当主线程空闲时,从队列中取出第一个任务并执行。
  4. 当任务完成时,如果有回调函数,则将其排入队列中。
  5. 重复步骤 1-4,直到主线程的任务完成。

例如,下面是一个使用事件循环的示例:

console.log('Start');
setTimeout(function() {
  console.log('Timeout');
}, 1000);
console.log('End');

在这个例子中,事件循环会执行以下步骤:

执行 console.log('Start')。

遇到 setTimeout 函数,将其排入队列中。

执行 console.log('End')

一秒钟后,从队列中取出第一个任务并执行 console.log('Timeout')。


20、防抖和节流

防抖和节流是两种常见的控制函数执行频率的方法,常用于限制用户的输入频率或频繁触发的事件。

防抖(debouncing)是指在一定时间内只执行最后一次触发事件,在这个时间内如果有新的触发事件,会取消之前的触发事件并重新计时。防抖通常用于限制输入频率,比如在输入框中输入文本,或者在搜索框中输入关键字。

节流(throttling)是指在一定时间内只执行一次事件,在这个时间内如果有新的触发事件,会忽略这个事件,等到这个时间结束后才会执行。节流通常用于限制事件触发的频率,比如在滚动条事件中执行实时网络请求,调整窗口大小事件等。

以下是一个简单的防抖函数的实现:

function debounce(func, delay) {
  let timeout;
  return function() {
    const context = this;
    const args = arguments;
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      func.apply(context, args);
    }, delay);
  }
}

使用方法:

const input = document.querySelector('input');
input.addEventListener('input', debounce(() => {
  console.log('Debounced input event');
}, 500));

以下是一个简单的节流函数的实现:

function throttle(func, delay) {
  let lastCall = 0;
  return function() {
    const context = this;
    const args = arguments;
    const currentTime = Date.now();
    
    if (lastCall + delay < currentTime) {
      lastCall = currentTime;
      func.apply(context, args);
    }
  }
}

使用方法:

const input = document.querySelector('input');
input.addEventListener('input', throttle(() => {
  console.log('Throttled input event');
}, 500));


需要注意的是,防抖和节流的效果是有区别的。防抖会延迟执行函数,直到输入停止一段时间后才执行;而节流会保证函数在一定时间内只执行一次,如果在这段时间内有多次触发事件,只有第一次会被执行。根据实际需求来选择使用防抖还是节流。

21、ES6新增方法


  • ECMAScript 6(也称为 ECMAScript 2015)是 JavaScript 的下一代标准,提供了很多新的特性。下面是一些常见的新增特性:
  • letconst 关键字:这两个关键字用于声明变量,其中 let 声明的变量可以被修改,而 const 声明的变量是常量,不能被修改。
  • 箭头函数(Arrow functions):这是一种简化函数的语法,它比传统的函数定义更短、更简洁。例如,你可以使用箭头函数来声明一个简单的函数,如下所示:
const greet = name => `Hello, ${name}!`;
  • 块级作用域:在 ES6 中,你可以使用 letconst 在代码块(如 for 循环或 if 语句)内声明变量。这意味着这些变量只在声明它们的代码块内可用,而不是整个函数内可用。
  • 类(Classes):ES6 中引入了类的概念,使得创建和维护对象变得更加容易。你可以使用类来声明新的对象类型,并使用类的构造函数来创建新的对象实例。
  • 模板字符串(Template literals):模板字符串是一种新的字符串表示方式,使用反引号(`)包围,允许模板字符串内插变量。例如,你可以使用如下的模板字符串来创建带有变量的字符串:
const name = 'John'; console.log(`Hello, ${name}!`); // 输出 "Hello, John!"
  • 解构赋值(Destructuring assignment):解构赋值是一种方便的方法,可以在一个表达式中提取数组或对象的多个值。例如,你可以使用解构赋值将对象的属性赋值给变量,如下所示:
const user = {   name: 'John',   age: 30 }; const { name, age } = user; console.log(name); // 输出 "John" console.log(age); // 输出 30

这些只是 ES6 中的一些新增特性,还有许多其他的特性,例如 Promises、Iterators、Generators、Modules 等。


22、set和map的区别

JavaScript 中的 Set 和 Map 是两种常用的数据结构,它们都是用于存储数据的容器,但是它们有一些区别。

Set:

  • Set 是一种无序的数据集合,其中的元素都是唯一的。Set 中的元素可以是任意类型的值。
  • Set 支持的操作包括添加、删除、查找和枚举,可以使用 for-of 循环来遍历 Set 中的所有元素。
  • Set 是一种新的数据结构,它在 ECMAScript 2015 中引入。

Map:

  • Map 是一种无序的键值对集合,其中的元素都是以键值对的形式存储的。Map 中的键和值可以是任意类型的值。
  • Map 支持的操作包括添加、删除、查找和枚举,可以使用 for-of 循环来遍历 Map 中的所有元素。
  • Map 也是一种新的数据结构,它在 ECMAScript 2015 中引入。

在使用时,应根据实际需求来选择使用 Set 或 Map。如果你需要存储一组唯一的数据,可以使用 Set;如果你需要存储一组键值对数据,可以使用 Map。

以下是一个简单的 Set 的使用示例:

const set = new Set([1, 2, 3, 4, 5]);
console.log(set.has(3));  // true
console.log(set.has(6));  // false
set.add(6);
set.delete(5);
for (const value of set) {
  console.log(value);
}

在这个示例中,我们创建了一个 Set 对象,并通过构造函数传入了一个数组 [1, 2, 3, 4, 5]。然后我们使用 Set 的 has() 方法来检查 Set 中是否存在某个元素。接下来我们使用 add() 方法向 Set 中添加一个新元素 6,并使用 delete() 方法删除 Set 中的元素 5。最后我们使用 for-of 循环遍历 Set 中的所有元素。

以下是一个简单的 Map 的使用示例:

const map = new Map([
  ['name', 'John'],
  ['age', 30]
]);
console.log(map.get('name'));  // John
console.log(map.get('age'));   // 30
map.set('country', 'USA');
map.delete('age');
for (const [key, value] of map) {
  console.log(`${key}: ${value}`);
}

在这个示例中,我们创建了一个 Map 对象,并通过构造函数传入了一个数组 [ ['name', 'John'], ['age', 30] ]。然后我们使用 Map 的 get() 方法来获取 Map 中的元素值。接下来我们使用 set() 方法向 Map 中添加一个新的键值对 ['country', 'USA'],并使用 delete() 方法删除 Map 中的键值对 ['age', 30]。最后我们使用 for-of 循环遍历 Map 中的所有元素。

23、点击穿透现象及解决办法

点击穿透是指在使用移动设备浏览网页时,当用户点击屏幕上的某一元素时,点击事件会同时触发下方的元素。这种现象通常发生在设计中使用了透明或半透明背景的元素上。

要解决这个问题,你可以采取以下几种方法:

  1. 使用不透明的背景:为触发点击穿透的元素使用不透明的背景,这样就不会出现点击穿透的现象了。
  2. 给元素添加边框:为触发点击穿透的元素添加边框,这样就可以使用边框来阻止点击事件穿透到下方的元素。
  3. 使用 JavaScript 来阻止点击穿透:可以使用 JavaScript 代码来阻止点击事件穿透到下方的元素。你可以在元素上添加一个点击事件监听器,并在事件处理函数中调用 event.preventDefault() 方法来阻止默认的点击行为。
  4. 使用 CSS 属性 pointer-events: none:你可以使用这个 CSS 属性来禁用元素的点击事件。这样就可以阻止点击穿透的现象了。
  5. 使用 CSS 伪类 :active:你可以使用 :active 伪类来模拟点击效果,从而避免点击穿透的现象。你可以在元素的样式中使用 :active 伪类来设置点击时的样式,例如:
button:active {
  background-color: blue;
}

这样,当用户点击按钮时,按钮的背景颜色会变成蓝色。这种方法可以在不使用 JavaScript 的情况下解决点击穿透的问题。

总之,点击穿透是一个常见的问题,但是有很多方法可以解决这个问题。你可以根据自己的需求来选择最合适的方法来解决点击穿透的问题。

24、js的继承

  • 原型链继承:让新实例的原型等于父实例
  • 可继承:实例的构造函数的属性,父类构造函数属性,以及父类原型的属性
  • 不可继承:父类实例的属性
  • 借用构造函数继承:使用 apply()和 call()方法将父类构造函数引入子类函数
  • 可继承:父类构造函数的属性
  • 不可继承父类原型的属性
  • 组合继承:将原型链和借用构造函数的技术组合在一块,从而发挥两者之长的一种继承模式
  • 原型式继承:借助原型可以基于已有的对象创建新对象,类似复制了一个对象
  • 寄生式继承:就是给原型式继承外面套个壳子,没用到原型
  • 寄生组合式继承:通过借用函数来继承属性,通过原型链的混成形式来继承方法(常用)

25、如何理解promise

Promise 是一种用于异步编程的解决方案,它可以让你以同步的方式编写异步代码。

在 JavaScript 中,很多操作都是异步的,例如网络请求、读取文件或等待用户输入。这些操作会在后台运行,因此你不能直接等待它们完成,而是需要提供一个回调函数,在操作完成时调用。

Promise 可以解决这种回调地狱的问题,它使用一种称为链式调用的方法,让你能够在 then 方法中连续调用多个异步操作。

例如,你可以使用 Promise 发起一个网络请求,然后在请求完成后调用回调函数。你可以使用 then 方法来处理请求结果,如下所示:

axios.get('http://example.com/movies.json')
  .then(response => response.json())
  .then(data => console.log(data))   
  .catch(error => console.error(error));

在这个例子中,axios.get 方法会发起一个网络请求,然后返回一个 Promise。你可以在 then 方法中提供一个回调函数来处理响应数据,然后再次使用 then 方法来处理解析后的数据。如果在任何阶段发生错误,你可以使用 catch 方法来处理错误。

这种方法使得异步编程变得更加简单,因为你不再需要写很多嵌套的回调函数。你可以使用 then 方法链式调用多个异步操作,而不用担心回调地狱的问题。

Promise 还有一些其他的特性,例如你可以使用 Promise.all 方法来并行执行多个 Promise,或者使用 Promise.race 方法来执行多个 Promise 中最先完成的那个。你还可以使用 Promise.resolve 和 Promise.reject 方法来创建已完成或已拒绝的 Promise。

总之,Promise 是一种有用的工具,可以让你在异步编程中更加简单、灵活地处理异步操作。

相关文章
|
7天前
|
Java Go 开发者
IDEA开发常用的快捷键
IntelliJ IDEA常用快捷键汇总:涵盖代码生成(如main、sout)、编辑(复制、删除、重命名)、导航(跳转、查找)、格式化、代码阅读及版本控制等高频操作,提升开发效率。熟练掌握可显著优化编码体验,是Java开发者必备技能。
136 1
|
7天前
|
Oracle Java 关系型数据库
Java命名规范
Java命名规范涵盖包、类、方法、变量等命名规则。包名全小写,类名首字母大写采用驼峰法,接口常用形容词,抽象类以Abstract/Base开头,异常类以Exception结尾,方法名小写驼峰,常量全大写用下划线分隔,枚举值按常量规范命名,提升代码可读性与一致性。
104 0
|
10天前
|
JavaScript 前端开发 关系型数据库
|
10天前
|
测试技术
发布模式
cascascas
17 0
|
10天前
|
SQL 关系型数据库 MySQL
|
10天前
|
Arthas 运维 监控
|
10天前
|
存储 缓存 数据建模
|
10天前
|
Java 开发工具 数据安全/隐私保护
|
10天前
|
负载均衡 Dubbo 应用服务中间件

热门文章

最新文章