Bootstrap

【2024最新版】JavaScript前端面试篇,看这一篇就够了

在这里插入图片描述


更多相关内容可查看

以下面试内容皆为2024年各大网站的面经题目,答案均为自己或gpt整理,并会不断补充

javascript基本数据类型都有什么

JavaScript有七种基本数据类型,它们是:

  • Number:用于任何数值。包括整数和浮点数。
  • String:用于字符串,一个字符串可以包含一个或多个字符,比如 “hello” 或 “abc”。
  • Boolean:用于 true 或 false。
  • Null:用于未定义的值,只有一个 null 值的特殊类型。
  • Undefined:用于未赋值的变量,只有一个 undefined 值的特殊类型。
  • Symbol:用于唯一的标识符。
  • BigInt:用于存储任意长度的整数。
  • 除了这些基本数据类型,JavaScript还有 Object 类型,它是一种复合数据类型,可以用来存储多个值作为属性或者方法。

有一个下拉框,我如何给下拉框绑定点击事件而不触发它的下拉选择事件

在JavaScript中,你可以使用event.stopPropagation()方法来阻止事件冒泡,这样就可以防止触发下拉选择事件。以下是一个基本的示例:

<select id="mySelect">
  <option value="option1">Option 1</option>
  <option value="option2">Option 2</option>
  <option value="option3">Option 3</option>
</select>

<script>
var selectElement = document.getElementById('mySelect');

selectElement.addEventListener('click', function(event) {
  event.stopPropagation();
  // 在这里添加你的点击事件处理代码
  console.log('Clicked!');
});
</script>

在这个示例中,我们首先获取了下拉框元素,然后为它添加了一个点击事件监听器。在事件监听器中,我们首先调用了event.stopPropagation()方法来阻止事件冒泡,然后添加了我们自己的点击事件处理代码。

请注意,event.stopPropagation()方法只能阻止事件冒泡,不能阻止事件本身。也就是说,如果你的下拉框有一个单独的选择事件监听器,那么这个监听器仍然会被触发。如果你想完全阻止下拉选择事件,你可能需要使用其他方法,比如修改下拉框的disabled属性或者使用自定义的下拉框组件。

js中this的概念

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

  1. 在全局作用域或函数外部调用 this,它通常指向全局对象,在浏览器中就是 window
console.log(this);  // Window {...}
  1. 当函数作为对象的方法被调用时,this 指向调用该方法的对象。
var obj = {
  name: 'My Object',
  showThis: function() {
    console.log(this);
  }
};
obj.showThis();  // {name: "My Object", showThis: ƒ}
  1. 在构造函数中,this 指向新创建的对象实例。
function MyConstructor() {
  this.name = 'My Instance';
  console.log(this);
}
var instance = new MyConstructor();  // MyConstructor {name: "My Instance"}
  1. 当使用 callapply 方法调用函数时,this 指向我们传递给 callapply 的第一个参数。
function showThis() {
  console.log(this);
}
showThis.call({name: 'My Object'});  // {name: "My Object"}
  1. 在事件处理函数中,this 通常指向触发事件的元素。
button.addEventListener('click', function() {
  console.log(this);  // 指向触发点击事件的 button 元素
});
  1. 在箭头函数中,this 是词法绑定的,它的值由外围最近一层非箭头函数决定。
var obj = {
  name: 'My Object',
  showThis: function() {
    var arrowFunc = () => console.log(this);
    arrowFunc();
  }
};
obj.showThis();  // {name: "My Object", showThis: ƒ}

需要注意的是,this 的值在函数定义时是不能确定的,只有当函数被调用时,this 的值才能确定。

Promise的方法有哪些?

Promise 是 JavaScript 中用于处理异步操作的对象,它有以下的方法:

  1. Promise.resolve(value):返回一个以给定值解析后的 Promise 对象。如果这个值是一个 promise,那么将返回这个 promise;如果这个值是 thenable(即,有 “then” 方法的对象),返回的 promise 会“跟随”这个 thenable 的对象,采用它的最终状态;否则返回的 promise 将以此值完成。此函数将类 promise 对象的多层嵌套展平。

  2. Promise.reject(reason):返回一个带有拒绝原因的 Promise 对象。

  3. Promise.all(iterable):这个方法返回一个新的 promise 对象,该 promise 会在 iterable 参数内所有的 promise 都完成(resolve)或有一个 promise 失败(reject)时被解决(resolve)或失败(reject)。返回值的结果顺序与传入的 promise 位置顺序一致(并非解决的顺序)。

  4. Promise.race(iterable):这个方法返回一个 promise,一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝。

  5. Promise.allSettled(iterable):这个方法返回一个 promise,这个 promise 在所有的输入的 promise 都被 settle 后,无论是 fulfilled 还是 rejected,才会被 resolve。

  6. Promise.any(iterable):这个方法返回一个 promise,只要给定的迭代中的一个 promise 成功,无论其他 promise 是否失败,都会进入成功状态。

  7. Promise.prototype.then(onFulfilled, onRejected):为 Promise 添加解决(fulfillment)和拒绝(rejection)回调,并返回一个新的 promise,解决时返回的是 onFulfilled 的返回值,拒绝时返回的是 onRejected 的返回值。

  8. Promise.prototype.catch(onRejected):为 Promise 添加一个拒绝(rejection)回调,并返回一个新的 promise,解决时返回原 promise 的解决值,拒绝时返回的是 onRejected 的返回值。

  9. Promise.prototype.finally(onFinally):为 Promise 添加一个无论 Promise 对象最后状态如何都会执行的回调,并返回一个新的 promise。

前端优化有哪些手段?

前端优化是一个涵盖多个方面的过程,以下是一些常见的优化手段:

  1. 压缩和合并文件:通过工具如 UglifyJS 和 CSSNano 对 JavaScript 和 CSS 进行压缩,减少文件大小。同时,可以将多个文件合并为一个文件,减少 HTTP 请求的数量。

  2. 使用 CDN:使用内容分发网络(CDN)可以将静态资源分布到世界各地的服务器上,使用户可以从地理位置最近的服务器获取资源,从而加快加载速度。

  3. 优化图片:对图片进行压缩,或者根据设备和视口大小提供适当的图片,可以大大减少加载时间。

  4. 使用缓存:通过设置 HTTP 缓存头,可以使浏览器在一段时间内不需要重新请求已经获取过的资源。

  5. 代码分割和懒加载:通过将代码分割成多个小的、按需加载的包,可以减少首次加载的时间。懒加载则是指只有当资源实际需要时才加载它。

  6. 优化 CSS:将关键的 CSS 内联到 HTML 中,可以加快首次渲染的速度。同时,避免使用昂贵的 CSS 选择器和过度的嵌套,可以提高渲染性能。

  7. 优化 JavaScript:避免使用昂贵的操作,如 DOM 操作和布局重排。使用 Web Workers 进行复杂的计算,可以避免阻塞主线程。

  8. 使用服务端渲染(SSR)或预渲染:这可以使用户更快地看到首次渲染的页面,提高 perceived performance。

  9. 优化 Web 字体:Web 字体可能会阻塞渲染,所以应尽量减少其使用,或者使用 font-display 属性来控制其加载行为。

  10. 使用性能 API:使用 Performance API、Navigation Timing API 等工具来监控和分析性能问题。

什么是闭包?

在 JavaScript 中,当一个函数(我们称之为外部函数)返回另一个函数(内部函数)时,内部函数会保留对外部函数作用域的引用,这样即使外部函数已经执行完毕,内部函数仍然可以访问到外部函数的作用域,这就形成了一个闭包。

闭包有很多用途,比如:

  1. 创建私有变量:JavaScript 中没有原生的私有变量概念,但我们可以使用闭包来模拟私有变量。

  2. 实现持久化的局部变量:正常情况下,函数的局部变量在函数执行完毕后就会被销毁,但如果我们将这个局部变量通过闭包暴露出去,那么这个局部变量就会一直存在。

  3. 实现数据封装和信息隐藏。

这是一个简单的闭包例子:

function outerFunction() {
  let count = 0;
  return function innerFunction() {
    count++;
    console.log(count);
  }
}

let counter = outerFunction();
counter();  // 输出:1
counter();  // 输出:2

在这个例子中,innerFunction 是一个闭包,它保留了对 outerFunction 作用域中 count 变量的引用。

页面上同时渲染大量图片,如何做性能优化

当页面上需要渲染大量图片时,可以采取以下几种方法进行性能优化:

  1. 图片懒加载:只有当图片进入视口时,才开始加载图片。这可以减少页面初次加载时的网络请求和计算量。

  2. 使用缩略图:如果图片本身的分辨率很高,但在页面上显示的尺寸却很小,那么可以考虑使用缩略图。用户在需要查看高清大图时,再去请求原图。

  3. 图片压缩:减少图片的文件大小,可以加快图片的加载速度。可以使用一些工具进行无损压缩或者有损压缩。

  4. 使用CDN:通过内容分发网络(CDN)可以加快图片的加载速度。CDN会将资源缓存到离用户最近的服务器,当用户请求资源时,可以从最近的服务器获取,从而减少延迟。

  5. 图片格式选择:根据使用场景选择合适的图片格式。例如,如果图片有很多颜色,可以使用JPEG;如果图片颜色较少,可以使用PNG;如果需要动态图片,可以使用GIF。

  6. 使用Sprite图:将多个小图标合并到一张大图中,通过CSS的background-position属性来显示需要的图标,可以减少HTTP请求的次数。

  7. 预加载:对于一些重要的、必须显示的图片,可以使用预加载技术,提前加载这些图片,保证在需要的时候能够立即显示。

  8. 使用WebP格式:WebP格式的图片比PNG和JPEG格式的图片具有更小的体积,在不损失质量的情况下可以提高加载速度。但需要注意的是,并非所有的浏览器都支持WebP格式。

以上就是一些常见的优化方法,具体使用哪种方法,需要根据实际情况来决定。

懒加载如果不用框架,你如何手写懒加载

懒加载,也称延迟加载,主要用于提高页面加载速度和优化用户体验。以下是一个简单的手写懒加载的实现方法:

  1. 首先,我们需要在HTML中为需要懒加载的图片添加特殊的标记,例如使用data-src代替src来存储图片的真实地址:
<img data-src="image.jpg" alt="Some image">
  1. 然后,在JavaScript中,我们可以使用IntersectionObserver API来检测图片是否进入了视口。如果图片进入了视口,我们就将data-src的值赋给src,这样图片就会开始加载:
let images = document.querySelectorAll('img[data-src]');

let observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      let img = entry.target;
      img.src = img.getAttribute('data-src');
      img.removeAttribute('data-src');
      observer.unobserve(img);
    }
  });
});

images.forEach(img => observer.observe(img));

以上就是一个简单的懒加载实现。需要注意的是,IntersectionObserver API在一些旧的浏览器中可能不被支持,因此在生产环境中使用时可能需要添加一些兼容性处理。

图片加载过程中出现加载失败怎么解决

在循环渲染时,渲染中间某一项的图片假如说网络断了一下,没加载出来,如何找到对应的那一项并重新渲染那一项?

在循环渲染时,如果某一项的图片由于网络问题没有加载出来,可以通过监听图片的onerror事件来处理。当图片加载失败时,onerror事件会被触发。

以下是一个简单的示例:

let images = document.querySelectorAll('img');

images.forEach(img => {
  img.onerror = function() {
    // 图片加载失败,重新加载
    this.src = 'fallback.jpg';  // fallback.jpg 是备用图片,也可以重新设置为原图片地址尝试重新加载
  };
});

在这个示例中,当图片加载失败时,我们将图片的src设置为一个备用图片的地址。你也可以根据需要进行其他处理,例如重新设置为原图片地址尝试重新加载。

如果你需要找到这个图片对应的数据项,可以在渲染时将数据项的信息存储在图片元素的自定义属性中,这样在onerror事件中就可以获取到。

例如:

// 假设 data 是你的数据数组
data.forEach((item, index) => {
  let img = document.createElement('img');
  img.dataset.index = index;  // 存储数据项的索引
  img.src = item.imageSrc;
  img.onerror = function() {
    console.log('加载失败的数据项索引:', this.dataset.index);
    // 这里可以进行其他处理,例如重新加载图片
  };
  document.body.appendChild(img);
});

在这个示例中,我们将数据项的索引存储在图片元素的data-index属性中。当图片加载失败时,我们可以从onerror事件处理函数中的this.dataset.index获取到。

symbol怎么使用

Symbol 是 ES6 引入的一种新的原始数据类型,表示独一无二的值。它的主要用途是作为对象属性的键,防止属性名冲突。

创建 Symbol:

let sym1 = Symbol();
let sym2 = Symbol('description'); // 可选的字符串描述,主要用于调试

注意,Symbol 函数前不能使用 new 命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。

Symbol 作为属性键:

let sym = Symbol('key');
let obj = {
  [sym]: 'value'
};

console.log(obj[sym]); // 'value'

注意,Symbol 作为属性键时,不能用点运算符,必须放在方括号中。

获取对象的 Symbol 属性:

let sym = Symbol('key');
let obj = {
  [sym]: 'value',
  key: 'value2'
};

let symbols = Object.getOwnPropertySymbols(obj); // [Symbol(key)]

console.log(obj[symbols[0]]); // 'value'

注意,Object.getOwnPropertySymbols 方法可以获取到对象的所有 Symbol 属性,但是不能获取到其他属性。如果要获取到对象的所有属性,包括 Symbol 属性,可以使用 Reflect.ownKeys 方法。

以上就是 Symbol 的基本用法。需要注意的是,由于 Symbol 的值是独一无二的,因此不能与其他值进行运算,也不能与其他值进行强制类型转换,否则会报错。

了解过哪些攻击方式

在前端开发中,常见的攻击方式主要有以下几种:

  1. XSS(跨站脚本攻击):攻击者在网页中注入恶意的脚本,当其他用户浏览该网页时,注入的脚本会被执行,从而达到攻击的目的。防御方式主要是对用户输入进行过滤和转义,以及使用CSP(内容安全策略)等技术。

  2. CSRF(跨站请求伪造):攻击者诱导用户点击链接,利用用户的登录状态发起恶意请求。防御方式主要是使用CSRF Token,或者进行Samesite Cookie设置。

  3. 点击劫持:攻击者通过透明的元素或者iframe,诱导用户点击其预设的操作,而用户以为自己是在正常操作。防御方式主要是使用X-Frame-Options HTTP响应头,或者进行Framebusting处理。

  4. 中间人攻击:攻击者在用户和服务器之间插入自己,截取或者篡改通信内容。防御方式主要是使用HTTPS等加密通信方式。

  5. DNS劫持:攻击者通过篡改DNS服务器,将用户导向到恶意网站。防御方式主要是使用HTTPS,以及对DNS进行加密等。

  6. SQL注入:攻击者通过输入恶意的SQL语句,对数据库进行非法操作。防御方式主要是对用户输入进行过滤和转义,以及使用参数化查询等。

在开发中对安全性有哪些考虑

  1. 输入验证:所有用户输入的数据都应该被视为不可信的,需要进行适当的验证和清理。这包括对输入长度、格式和类型的检查,以及对潜在的恶意代码的清理。

  2. 输出转义:为了防止跨站脚本(XSS)攻击,应该对所有输出到浏览器的内容进行适当的转义。

  3. 使用HTTPS:为了保护数据在传输过程中的安全,应该使用HTTPS协议。这不仅可以防止数据被窃听,还可以防止数据被篡改。

  4. 使用安全的cookie:应该将cookie设置为HttpOnly和Secure,以防止cookie被窃取或在非安全的连接上发送。

  5. 防止跨站请求伪造(CSRF):可以通过使用CSRF令牌或者进行SameSite Cookie设置来防止CSRF攻击。

  6. 使用内容安全策略(CSP):CSP可以限制浏览器只加载和执行来自特定源的脚本,从而防止XSS攻击。

  7. 防止SQL注入:应该使用参数化查询或者预编译的SQL语句,而不是直接拼接SQL语句。

  8. 使用最新的安全补丁:应该定期更新系统和软件的安全补丁,以防止已知的安全漏洞被利用。

  9. 最小权限原则:应该尽量限制系统和用户的权限,只赋予完成任务所必需的最小权限。

  10. 密码安全:应该使用强密码,并且不应该明文存储密码,而是存储密码的哈希值。同时,应该提供密码找回和修改的安全机制。

以上是一些基本的安全考虑,具体的实施可能需要根据实际的应用场景和需求进行调整。

一个好的界面应该是什么样的

一个好的界面设计应该考虑以下几个方面:

  1. 用户友好:界面应该简洁明了,易于理解和操作。用户应该能够快速地找到他们需要的信息或功能,而不需要花费太多的时间和精力。

  2. 一致性:在整个应用或网站中,设计元素和布局应该保持一致。这包括字体、颜色、按钮样式、图标、间距等。一致的设计可以帮助用户建立对界面的认知,提高使用效率。

  3. 反馈:用户的每一个操作都应该有明确的反馈,例如点击按钮后的动画效果,或者提交表单后的提示信息。这可以让用户知道他们的操作是否成功,以及下一步应该做什么。

  4. 可访问性:界面应该考虑到所有用户的需求,包括视觉障碍、听力障碍等残障用户。例如,可以提供足够的颜色对比度,以及适当的字体大小。

  5. 响应式设计:随着移动设备的普及,一个好的界面应该能够在不同的设备和屏幕尺寸上都能正常工作。响应式设计可以确保界面在各种环境中都能提供良好的用户体验。

  6. 高性能:界面的加载和响应速度应该尽可能快。用户通常不愿意等待慢速的界面加载,这可能会导致他们离开你的应用或网站。

  7. 清晰的导航:用户应该能够容易地理解如何在应用或网站中导航。导航菜单应该清晰明了,位置易于找到。

  8. 美观:虽然这是主观的,但好的界面设计应该是吸引人的。美观的设计可以提高用户的满意度,使他们更愿意使用你的产品。

说一下对盒模型的理解?

在CSS中,盒模型是一种用来设计和布局的基本概念。每个HTML元素都可以看作是一个盒子,这个盒子由内容、内边距(padding)、边框(border)和外边距(margin)四个部分组成。

  1. 内容(Content):这是盒子的核心部分,包含了实际的内容,如文本、图片等。

  2. 内边距(Padding):内容区域周围的空白区域,内边距是透明的。

  3. 边框(Border):围绕在内边距和内容区域的线。边框是可见的,你可以定义它的颜色、宽度和样式。

  4. 外边距(Margin):边框外部的空白区域,用来隔开盒子与其他元素,外边距是透明的。

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

  • 标准盒模型:宽度和高度指的是内容区域的宽度和高度,不包括内边距、边框和外边距。总盒子的宽度和高度是由内容、内边距和边框的宽度和高度之和决定的。

  • IE盒模型:宽度和高度指的是内容区域、内边距和边框的总和。这意味着如果你增加内边距或边框的宽度,内容区域的宽度会相应减小。

在CSS3中,我们可以通过box-sizing属性来选择使用哪种盒模型。默认值是content-box,即标准盒模型;如果设置为border-box,则使用IE盒模型。

盒子的水平垂直居中怎么实现

实现盒子的水平垂直居中有多种方法,以下是一些常见的实现方式:

  1. 使用Flexbox布局:
.parent {
  display: flex;
  justify-content: center; /* 水平居中 */
  align-items: center; /* 垂直居中 */
}
  1. 使用CSS Grid布局:
.parent {
  display: grid;
  justify-content: center; /* 水平居中 */
  align-items: center; /* 垂直居中 */
}
  1. 使用定位和transform:
.parent {
  position: relative;
}

.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
  1. 使用定位和margin:
.parent {
  position: relative;
}

.child {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
}
  1. 使用table-cell和vertical-align:
.parent {
  display: table-cell;
  text-align: center;
  vertical-align: middle;
}

以上方法可以根据实际的布局需求和浏览器兼容性要求进行选择。

http2 和 http1.1的区别?

HTTP/2 和 HTTP/1.1 之间有几个主要的区别:

  1. 多路复用:HTTP/2 支持多路复用,这意味着在同一个TCP连接上可以并行发送多个请求或接收多个响应。这可以减少网络延迟,提高页面加载速度。而在 HTTP/1.1 中,每个请求/响应都需要建立一个新的TCP连接,这会消耗更多的资源和时间。

  2. 二进制协议:HTTP/2 是一个二进制协议,而 HTTP/1.1 是一个文本协议。二进制协议更易于解析,更高效,更小的错误可能性。

  3. 头部压缩:HTTP/2 引入了 HPACK 压缩,可以压缩请求和响应的头部,减少了无效的网络传输。

  4. 服务器推送:HTTP/2 支持服务器推送,这意味着服务器可以主动向客户端发送资源,而不需要客户端明确的请求。

  5. 流优先级:HTTP/2 可以通过优先级和权重来优化资源的传输,使得重要的资源可以优先传输。

  6. 安全性:虽然 HTTP/2 本身并不强制使用 HTTPS,但是大多数浏览器只支持通过 HTTPS 使用 HTTP/2,这使得 HTTP/2 的实际使用更加安全。

总的来说,HTTP/2 相比于 HTTP/1.1,提供了更高效的传输机制,可以提高网页的加载速度,提升用户体验。

怎么创建一个dom

在JavaScript中,创建一个DOM元素可以通过以下步骤实现:

  1. 使用document.createElement()方法创建一个新的元素。这个方法接受一个参数,即你想要创建的元素的类型,如 ‘div’、‘a’、‘img’ 等。

    例如,创建一个新的div元素:

    var newDiv = document.createElement('div');
    
  2. 为新元素设置属性。你可以使用element.setAttribute()方法来设置元素的属性。

    例如,给新的div元素设置一个类名:

    newDiv.setAttribute('class', 'myDiv');
    
  3. 创建文本节点并添加到新元素中。你可以使用document.createTextNode()方法来创建一个新的文本节点,然后使用element.appendChild()方法将其添加到新元素中。

    例如,创建一个新的文本节点并添加到div元素中:

    var newContent = document.createTextNode('Hello, this is my new div!');
    newDiv.appendChild(newContent);
    
  4. 将新元素添加到DOM中。你可以使用element.appendChild()element.insertBefore()方法将新元素添加到现有的DOM结构中。

    例如,将新的div元素添加到body的末尾:

    document.body.appendChild(newDiv);
    

块级元素有什么

块级元素在网页设计中是非常重要的概念,它们主要有以下特性:

  1. 块级元素会独占一行,即使其内容并未占满整行,其后的元素也会被挤到下一行显示。
  2. 块级元素可以设置宽度(width)、高度(height)、内边距(padding)、外边距(margin)以及边框(border)。
  3. 块级元素可以包含内联元素和其他块级元素。

常见的块级元素有:

  • <div>:无特定语义的分区元素,常用于页面布局。
  • <p>:段落。
  • <h1> - <h6>:标题。
  • <ul><ol><li>:无序列表、有序列表和列表项。
  • <table>:表格。
  • <form>:表单。
  • <header><footer><article><section>:HTML5 新增的语义化元素。

需要注意的是,通过 CSS 的 display 属性,可以将块级元素设置为内联元素(inline),也可以将内联元素设置为块级元素(block)。

块元素、行内元素、行内块元素的区别

块级元素、行内元素和行内块级元素是HTML和CSS中的基本概念,它们的主要区别如下:

  1. 块级元素:

    • 默认情况下,块级元素会独占一行,即使其内容并未占满整行,其后的元素也会被挤到下一行显示。
    • 可以设置宽度、高度、内边距、外边距以及边框。
    • 可以包含内联元素和其他块级元素。
    • 常见的块级元素有 <div>, <p>, <h1>-<h6>, <ul>, <ol>, <li>, <table>, <form>等。
  2. 行内元素:

    • 行内元素不会独占一行,它们会按照顺序排列在同一行内,直到该行空间用完为止。
    • 不能设置宽度和高度(width和height无效),但可以设置水平方向的内边距、外边距以及边框。
    • 只能包含数据和其他行内元素。
    • 常见的行内元素有 <span>, <a>, <img>, <button>, <input>, <label>, <em>, <strong>等。
  3. 行内块级元素:

    • 行内块级元素(inline-block)是块级元素和行内元素的结合体,它在布局上表现为行内元素,但是可以设置宽度、高度、内边距、外边距以及边框。
    • 行内块级元素不会独占一行,它们会按照顺序排列在同一行内,直到该行空间用完为止。
    • 可以包含内联元素和其他块级元素。
    • 常见的行内块级元素有 <img>, <button>, <input>, <select>, <textarea>等。此外,任何元素都可以通过CSS的display属性设置为inline-block。

需要注意的是,通过 CSS 的 display 属性,可以将块级元素设置为内联元素(inline)、行内块级元素(inline-block),也可以将内联元素设置为块级元素(block)。

如何给一个行内元素设置高度

在默认情况下,行内元素的高度是由其字体大小(line-height)以及内部内容来决定的,我们不能直接通过设置height属性来改变其高度。但是,我们可以通过以下几种方式来给行内元素设置高度:

  1. 将行内元素转换为块级元素或者行内块级元素:通过设置CSS的display属性为block或者inline-block,可以将行内元素转换为块级元素或者行内块级元素,然后就可以通过设置height属性来改变其高度了。

例如:

span {
  display: inline-block;
  height: 50px;
}
  1. 使用line-height属性:如果你只是想改变行内元素的视觉高度,那么可以通过设置line-height属性来达到这个目的。这种方法不会改变元素的实际高度,但会改变元素的视觉高度。

例如:

span {
  line-height: 50px;
}
  1. 使用padding属性:你也可以通过设置行内元素的上下内边距(padding-top和padding-bottom)来改变其视觉高度。这种方法同样不会改变元素的实际高度,但会改变元素的视觉高度。

例如:

span {
  padding-top: 10px;
  padding-bottom: 10px;
}

需要注意的是,以上方法中的第一种方法会改变元素的display属性,可能会影响到布局,所以在使用时需要谨慎。

箭头函数和普通函数的区别

箭头函数和普通函数(也称为函数声明或函数表达式)在JavaScript中是非常常用的,它们的主要区别如下:

  1. 语法差异:箭头函数的语法比普通函数更简洁。普通函数需要使用关键字function,而箭头函数则使用=>符号。

    普通函数:

    function add(x, y) {
      return x + y;
    }
    

    箭头函数:

    const add = (x, y) => x + y;
    
  2. this绑定:箭头函数没有自己的this,它会捕获其所在上下文的this值作为自己的this值,而普通函数的this值则是在函数被调用时确定的,这是最主要的区别。

  3. arguments对象:箭头函数不绑定arguments对象,如果要使用参数列表,可以使用rest参数代替。而普通函数会自动绑定arguments对象。

  4. 构造函数:箭头函数不能用作构造函数,你不能使用new关键字调用箭头函数,否则会抛出错误。而普通函数则可以被用作构造函数。

  5. 原型:由于箭头函数不能被用作构造函数,所以它也没有prototype属性。而普通函数由于可以被用作构造函数,所以它有prototype属性。

  6. yield关键字:箭头函数不能包含yield关键字,所以不能用作生成器函数。而普通函数则可以包含yield关键字,可以被用作生成器函数。

  7. 方法定义:如果一个函数作为对象的方法,那么普通函数在非严格模式下,其this指向调用它的对象;在严格模式下,其this值为undefined。而箭头函数作为方法,其this总是指向定义时所在的对象。

讲一下变量提升

变量提升(Hoisting)是JavaScript中的一个特性,它意味着无论变量或者函数在哪里声明,都会被提升到其作用域的顶部。

这个特性对于变量声明(使用var关键字)和函数声明(使用function关键字)都适用,但是对于let和const关键字声明的变量以及函数表达式(包括箭头函数)则不适用。

具体来说:

  1. 对于使用var声明的变量,只有声明会被提升,初始化会留在原地。也就是说,如果你在声明之前访问该变量,它的值会是undefined。

例如:

console.log(x); // 输出:undefined
var x = 5;
  1. 对于函数声明,整个函数的定义都会被提升到作用域顶部。

例如:

console.log(add(1, 2)); // 输出:3
function add(x, y) {
  return x + y;
}
  1. 对于使用let和const声明的变量,它们也存在变量提升,但是在变量声明之前的区域被称为“暂时性死区”,在这个区域内访问变量会导致一个ReferenceError错误。

例如:

console.log(x); // 抛出ReferenceError错误
let x = 5;
  1. 对于函数表达式(包括使用var、let、const和箭头函数),只有使用var的函数表达式会被提升,并且只提升声明,不提升赋值。

例如:

console.log(add(1, 2)); // 抛出TypeError错误,因为add不是一个函数
var add = function(x, y) {
  return x + y;
}

弱网环境除了离线这种方案,还会有别的方案吗?

在弱网环境下,除了使用离线缓存技术来提高应用的性能和可用性外,还可以采取以下一些策略:

  1. 优化资源:减小文件的大小可以减少加载时间,这可以通过压缩和优化代码、图片等资源来实现。另外,还可以使用CDN(内容分发网络)来加速资源的加载。

  2. 懒加载:只加载用户需要的部分,当用户滚动到其他部分时再进行加载。这可以减少初次加载的资源数量,提高页面的加载速度。

  3. 异步加载:通过异步加载,可以在主要内容加载完毕后再加载其他资源,这样可以让用户尽快看到主要内容。

  4. 使用服务端渲染(SSR):服务端渲染可以将页面的初始状态直接输出到HTML中,这样可以减少浏览器端的计算量,提高页面的加载速度。

  5. 使用预加载和预渲染技术:预加载可以提前获取用户可能需要的资源,预渲染则可以提前渲染用户可能会访问的页面。

  6. 使用HTTP/2:HTTP/2支持多路复用,可以同时传输多个请求或响应,这可以减少网络延迟,提高加载速度。

  7. 使用骨架屏或者占位符:在内容加载完成前,先展示一个简单的骨架屏或者占位符,提高用户的感知速度。

  8. 对API进行优化:比如减少API请求的次数,使用GraphQL来避免过度获取数据等。

以上就是一些在弱网环境下提高网页性能的策略,具体使用哪种策略取决于具体的应用和场景。

小程序和h5移动端这些为了避免网络不好,避免渲染比较慢的一些体验,你有什么方案或者做过什么东西?

在开发小程序和H5移动端应用时,为了避免网络不好导致的渲染慢的问题,可以采取以下一些策略:

  1. 优化资源加载:减少文件大小,压缩图片和代码,使用CDN来加速资源的加载。

  2. 懒加载和预加载:懒加载是指只有当资源需要显示时才加载,预加载则是在后台提前加载用户可能会用到的资源。

  3. 异步操作:将一些非关键的操作放在后台异步执行,例如使用Web Workers进行后台处理。

  4. 缓存策略:利用浏览器的缓存机制,如HTTP缓存、Service Worker等,将静态资源缓存到本地,减少网络请求。

  5. 使用骨架屏:在内容加载完成前,先展示一个简单的骨架屏,提高用户的感知速度。

  6. 数据存储:对于一些不经常改变的数据,可以考虑使用本地存储,如localStorage、IndexedDB等。

  7. 服务端渲染(SSR):服务端渲染可以将页面的初始状态直接输出到HTML中,这样可以减少浏览器端的计算量,提高页面的加载速度。

  8. 请求优化:减少API请求的次数,合并请求,使用GraphQL来避免过度获取数据等。

在我之前的项目中,我主要是通过优化资源加载,使用懒加载和预加载,利用浏览器的缓存机制,以及优化API请求等方式来提高应用的性能。具体的策略会根据项目的具体需求和场景来确定。

打包文件的时候,怎么把每个包控制在1兆以内

在前端打包过程中,为了控制每个包的大小在1兆以内,可以采取以下一些策略:

  1. 代码拆分(Code Splitting):使用Webpack等打包工具的代码拆分功能,将代码分割成多个小的包,这样可以确保每个包的大小不会太大。例如,可以按路由进行代码拆分,每个路由对应一个代码包。

  2. Tree Shaking:这是一种只打包实际用到的代码的方法,可以有效地减小包的大小。

  3. 压缩和优化代码:使用UglifyJS、Terser等工具对代码进行压缩和优化,可以去除无用的代码和注释,减小包的大小。

  4. 懒加载:对于一些非关键的代码,可以使用懒加载的方式进行加载,这样可以减小初始包的大小。

  5. 使用Externals:将一些常用的库(如React、Vue等)通过externals的方式引入,而不是打包到代码中,这样可以减小包的大小。

  6. 分析并优化依赖:使用Webpack Bundle Analyzer等工具分析包的大小,找出占用空间大的依赖,然后考虑是否有更小的替代方案,或者是否可以只引入需要的部分。

  7. 使用CDN:将一些大的库或者资源放到CDN上,然后在页面中通过链接的方式引入,这样可以减小包的大小。

以上就是一些控制包大小的策略,具体使用哪种策略取决于项目的具体需求和场景。

;