前端面经真题解析8-海康/前端/超详细记录

1.CSS常用单位

在 CSS 中,常用的单位包括以下几种:

像素(px):像素是最常见的单位,它表示屏幕上的一个物理像素点。特点是精确度高,可以精确地控制元素的尺寸和位置。适用于绝大多数情况。

百分比(%):百分比单位是相对于父元素的大小来计算的。例如,使用宽度为 50% 的元素会占据其父元素宽度的一半。特点是可以根据父元素的大小自适应调整元素的尺寸。适用于响应式设计和相对布局。

em(em):em 是相对单位,相对于元素的字体大小(font-size)。1em 等于元素的字体大小。如果应用于父元素的字体大小上,那么子元素的 em 值就相对于父元素的字体大小来计算。特点是可以根据元素的字体大小进行相对调整。适用于响应式设计和相对布局。

rem(rem):rem 也是相对单位,相对于根元素(通常是 元素)的字体大小。1rem 等于根元素的字体大小。特点是可以根据根元素的字体大小进行相对调整,并且不会受到父元素字体大小的影响。适用于响应式设计和相对布局。

视窗单位(vw、vh、vmin、vmax):视窗单位是相对于浏览器窗口大小的单位。vw 表示视窗宽度的百分比,vh 表示视窗高度的百分比,vmin 表示视窗宽度和高度中较小的百分比**,vmax** 表示视窗宽度和高度中较大的百分比。特点是可以根据视窗大小进行相对调整,适用于响应式设计和全屏布局。

固定单位(pt、in、cm、mm):这些单位是绝对单位,表示固定的长度。pt 表示点(1/72 英寸),in 表示英寸,cm 表示厘米,mm 表示毫米。特点是不会随着屏幕大小或字体大小的变化而改变。适用于打印样式表或需要精确控制打印尺寸的情况。

选择使用哪种单位主要取决于具体的需求和设计目标。一般来说,像素(px)是最常用的单位,可以提供精确的控制。而百分比、em、rem 和视窗单位则适用于响应式设计和相对布局,可以根据不同屏幕尺寸和设备自适应地调整元素的尺寸。固定单位适用于需要精确控制尺寸的场景,如打印样式表。

2.数据量大时如何处理

当在前端处理大量数据时,可以采取以下几种策略来提高性能和用户体验:

1.数据分页:

将数据分为多个页面或分段加载,只在需要时请求并加载数据。这样可以减少一次性加载大量数据所带来的性能问题,并提高页面加载速度。可以使用分页组件或手动实现分页逻辑。

2.虚拟滚动:

对于长列表或表格,使用虚拟滚动技术只渲染可见部分的数据,而不是全部渲染。这可以减少DOM元素的数量,提高渲染性能。常见的虚拟滚动库包括react-virtualized和react-window。

3.数据缓存:

在前端使用缓存来存储已经获取到的数据,以避免重复请求相同的数据。可以使用浏览器的本地存储(如LocalStorage或SessionStorage)或者使用内存缓存库(如lru-cache)。

4.前端分片计算:

如果可能,可以将一些数据处理操作从前端转移到后端,以减轻前端的负担。例如,通过使用分布式计算或使用后端的数据聚合功能,可以减少前端处理大量数据的需求。

5.前端性能优化:

进行前端性能优化,减少不必要的渲染、减小JavaScript和CSS的文件大小、压缩资源、使用合适的图片格式等。这些优化可以减少数据传输和渲染所需的时间,提高前端性能。

6.增量加载和懒加载:

对于一些需要逐步加载的数据,可以采用增量加载或懒加载的方式。只在用户需要时加载新的数据块,而不是一次性加载全部数据。

7.Web Workers:

使用Web Workers可以将一些计算密集型任务放在后台线程中进行,避免阻塞主线程,提高页面的响应性能。Web Workers可以用于数据处理、计算、排序等任务。

以上策略可以根据具体情况的需求进行选择和组合。注意在实施前,评估性能瓶颈,并对关键代码进行性能测试和优化。

3.左边固定右边自适应的布局怎么实现(CSS)

在前端中实现左固定右自适应的两栏布局,有以下几种方案:

1.使用CSS的float属性:

可以将左侧固定栏设置为浮动(float: left;),右侧自适应栏设置为相对定位(position: relative;)并添加左边距(margin-left),使其避开左侧固定栏。

<style>
  .container {
    overflow: hidden;
  }

  .left {
    float: left;
    width: 200px; /* 左侧固定栏宽度 */
    background-color: #ccc;
  }

  .right {
    margin-left: 200px; /* 左侧固定栏宽度, 注意是margin-left 而不是 left */
    background-color: #f1f1f1;
  }
</style>

<div class="container">
  <div class="left">
    <!-- 左侧固定栏内容 -->
  </div>
  <div class="right">
    <!-- 右侧自适应栏内容 -->
  </div>
</div>

2.使用CSS的flexbox布局:

使用flexbox可以更方便地实现两栏布局,通过设置flex属性可以使左侧固定栏占据固定宽度,右侧自适应栏占据剩余空间。

<style>
  .container {
    display: flex;
  }

  .left {
    width: 200px; /* 左侧固定栏宽度 */
    background-color: #ccc;
  }

  .right {
    flex: 1; /* 右侧自适应栏占据剩余空间 */
    background-color: #f1f1f1;
  }
</style>

<div class="container">
  <div class="left">
    <!-- 左侧固定栏内容 -->
  </div>
  <div class="right">
    <!-- 右侧自适应栏内容 -->
  </div>
</div>

3.使用CSS的grid布局

使用CSS的grid布局也可以实现两栏布局,通过设置grid-template-columns属性可以将左侧固定栏和右侧自适应栏划分为两列。

<style>
  .container {
    display: grid;
    grid-template-columns: 200px 1fr; /* 左侧固定栏宽度,右侧自适应栏占据剩余空间 */
  }

  .left {
    background-color: #ccc;
  }

  .right {
    background-color: #f1f1f1;
  }
</style>

<div class="container">
  <div class="left">
    <!-- 左侧固定栏内容 -->
  </div>
  <div class="right">
    <!-- 右侧自适应栏内容 -->
  </div>
</div>

这些方案都能实现左固定右自适应的两栏布局,具体选择哪种方案取决于你的项目需求和使用习惯。

4.JS数组有哪些方法,从JS数组中删除指定元素怎么做(splice)

(1)js数组常用方法介绍

JavaScript数组有许多常用的方法,用于对数组进行操作和处理。下面是一些常见的JavaScript数组方法:

1.push(): 在数组末尾添加一个或多个元素,并返回修改后的数组长度。

2.pop(): 删除并返回数组的最后一个元素。

3.shift(): 删除并返回数组的第一个元素。

4.unshift(): 在数组开头添加一个或多个元素,并返回修改后的数组长度。

5.slice(): 返回一个新数组,其中包含从开始索引到结束索引(不包括结束索引)的元素。原数组不会被修改。

6.splice(): 从指定的索引位置开始,删除或替换指定数量的元素,并可以插入新的元素。

7.concat(): 返回一个新数组,其中包含原数组和一个或多个数组或值连接而成的元素。

8.join(): 将数组的所有元素连接成一个字符串,并返回该字符串。

9.indexOf(): 返回指定元素在数组中首次出现的索引,如果不存在则返回-1。

10.lastIndexOf(): 返回指定元素在数组中最后一次出现的索引,如果不存在则返回-1。

11.includes(): 判断数组是否包含指定元素,返回布尔值。

12.forEach(): 遍历数组的每个元素,并执行回调函数。

13.map(): 创建一个新数组,其中包含对原数组的每个元素应用回调函数后的结果。

14.filter(): 创建一个新数组,其中包含符合条件的原数组的元素。

15.reduce(): 对数组的每个元素执行回调函数,将结果累加为单个值。

16.reduceRight(): 与reduce()方法类似,但是从数组的最后一个元素开始向前迭代。

17.sort(): 对数组进行排序,默认按照字符串的Unicode码点进行排序。

18.reverse(): 反转数组的顺序。

(2)代码示例

1.push():

const arr = [1, 2, 3];
arr.push(4);
console.log(arr); // 输出: [1, 2, 3, 4]

2.pop():

const arr = [1, 2, 3];
const poppedElement = arr.pop();
console.log(arr); // 输出: [1, 2]
console.log(poppedElement); // 输出: 3

3.shift():

const arr = [1, 2, 3];
const shiftedElement = arr.shift();
console.log(arr); // 输出: [2, 3]
console.log(shiftedElement); // 输出: 1

4.unshift():

const arr = [2, 3];
arr.unshift(1);
console.log(arr); // 输出: [1, 2, 3]

5.slice():

const arr = [1, 2, 3, 4, 5];
const slicedArray = arr.slice(1, 4);
console.log(slicedArray); // 输出: [2, 3, 4]

6.splice():

const arr = [1, 2, 3, 4, 5];
const removedElements = arr.splice(1, 2, 'a', 'b');
console.log(arr); // 输出: [1, 'a', 'b', 4, 5]
console.log(removedElements); // 输出: [2, 3]

7.concat():

const arr1 = [1, 2];
const arr2 = [3, 4];
const newArr = arr1.concat(arr2);
console.log(newArr); // 输出: [1, 2, 3, 4]

8.join():

const arr = ['Hello', 'World'];
const joinedString = arr.join(' ');
console.log(joinedString); // 输出: "Hello World"

9.indexOf():

const arr = [1, 2, 3, 4, 5];
const index = arr.indexOf(3);
console.log(index); // 输出: 2

10.lastIndexOf():

const arr = [1, 2, 3, 4, 3, 5];
const lastIndex = arr.lastIndexOf(3);
console.log(lastIndex); // 输出: 4

11.includes():

const arr = [1, 2, 3, 4, 5];
const includesElement = arr.includes(3);
console.log(includesElement); // 输出: true

12.forEach():

const arr = [1, 2, 3];
arr.forEach(item => {
  console.log(item); // 输出: 1, 2, 3 (分别在每次循环中输出)
});

13.map():

const arr = [1, 2, 3];
const mappedArray = arr.map(item => item * 2);
console.log(mappedArray); // 输出: [2, 4, 6]

14.filter():

const arr = [1, 2, 3, 4, 5];
const filteredArray = arr.filter(item => item % 2 === 0);
console.log(filteredArray); // 输出: [2, 4]

15.reduce():

const arr = [1, 2, 3, 4, 5];
const sum = arr.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(sum); // 输出: 15

16.reduceRight():

const arr = ['H', 'e', 'l', 'l', 'o'];
const reversedString = arr.reduceRight((accumulator, currentValue) => accumulator + currentValue);
console.log(reversedString); // 输出: "olleH"

17.sort():

const arr = [3, 1, 4, 2, 5];
arr.sort();
console.log(arr); // 输出: [1, 2, 3, 4, 5]

18.reverse():

const arr = [1, 2, 3];
arr.reverse();
console.log(arr); // 输出: [3, 2, 1]

5.谈谈异步编程

(1)前端中的异步操作

在前端开发中,以下是一些常见的异步操作:

1.网络请求:包括通过AJAX、Fetch、Axios等方式发送HTTP请求,获取服务器上的数据。

2.定时器:使用setTimeout和setInterval函数设置定时器,在指定的时间间隔后执行回调函数或重复执行回调函数。

3.事件处理:例如点击事件、键盘事件、鼠标事件等用户交互行为触发的事件。

4.文件操作:包括读取文件、上传文件等与本地文件系统相关的操作。

5.异步函数和方法:某些函数和方法被设计为异步执行,例如使用setTimeout函数模拟的异步行为。

6.数据库操作:如果前端与数据库进行交互,例如通过Web API或本地数据库API进行数据的读取、写入或修改,这些操作通常是异步的。

7.动画效果:在前端开发中,通过CSS动画或JavaScript库(如jQuery、GSAP)创建的动画效果通常是异步的。

8.Promise和异步函数:Promise对象的使用和异步函数(async/await)的使用都是处理异步操作的常见方式。

需要注意的是,这些操作的异步性质意味着它们不会立即返回结果,而是需要等待一段时间或在某个事件触发后才能获取到结果。在处理异步操作时,合适的异步编程技术(如回调函数、Promise、async/await等)可以帮助我们更好地管理和处理这些异步操作。

(2)前端中的异步编程

异步编程通过使用回调函数、Promise、async/await等技术,使得程序能够在进行异步操作时不被阻塞,并在操作完成后执行相应的回调或继续执行下一步操作。

以下是一些前端中常见的异步编程技术:

1.回调函数(Callbacks):回调函数是异步编程最基本的形式。通过将函数作为参数传递给异步操作,并在操作完成后调用该函数,以实现异步操作的结果处理。然而,回调函数的嵌套层级可能会导致回调地狱(Callback Hell),使代码难以理解和维护。

2.Promise:Promise是一种用于管理异步操作的对象,它代表一个异步操作的最终完成(或失败)及其结果的值。Promise可以通过链式调用then()和catch()方法,使代码更具可读性和可维护性。

3.async/await:async/await是ES2017引入的异步编程语法糖,基于Promise实现。通过使用async关键字定义一个异步函数,并使用await关键字等待异步操作的结果,可以以更类似同步编程的方式编写异步代码。async/await提供了更简洁、可读性更好的异步编程体验。

4.Event-Driven Programming(事件驱动编程):事件驱动编程是基于事件和事件处理程序的编程模式。通过将回调函数注册为特定事件的处理程序,可以响应异步操作或用户交互触发的事件。

5.Observables(观察者模式):Observables是一种异步编程的抽象概念,用于处理未来可能发生的一系列事件或数据流。它可以订阅和取消订阅事件,并在事件发生时触发相应的操作。

6.加载白屏是什么原因

前端页面白屏是指在加载网页时,页面内容未能正确显示,而是呈现空白的情况。可能导致前端页面白屏的原因有很多,以下是一些常见的原因:

1.JavaScript错误:如果在页面加载或执行JavaScript代码时发生错误,可能会导致页面无法正确渲染,从而显示为空白。

2.CSS问题:CSS代码错误或加载失败可能会导致页面无法正确样式化,导致页面呈现为空白。

3.HTML结构问题:如果HTML代码存在错误或未正确闭合标签,可能会导致页面无法正确解析,导致页面呈现为空白。

4.资源加载问题:如果页面依赖的外部资源(例如CSS文件、JavaScript文件、图像等)加载失败或路径错误,可能会导致页面无法正确显示。

5.异步操作问题:如果页面中的异步操作(例如AJAX请求、定时器等)出现问题,可能会导致页面无法正确渲染。

6.缓存问题:浏览器缓存可能会导致页面呈现为空白,因为浏览器可能会尝试加载缓存的页面而不是实际的更新页面。

7.网络问题:网络连接不稳定或网络延迟可能导致页面加载过程中出现问题,导致页面呈现为空白。

8.性能问题:如果页面包含大量复杂的DOM元素、大型图像或耗时的脚本,可能会导致页面加载时间过长,给用户造成白屏的印象。

以上只是一些可能导致前端页面白屏的常见原因,实际情况可能因具体的代码、浏览器环境和网络条件而有所不同。在调试和解决前端页面白屏问题时,可以使用浏览器的开发者工具进行排查和错误定位,查看控制台输出、网络请求情况等来帮助分析问题所在。

7.Vue子传父,父传子,兄弟组件传数据怎么做

父传子 -->props
子传父 -->$emit
兄弟组件之间 -->事件总线,Vuex

8.Promise怎么用

Promise是JavaScript中用于处理异步操作的一种机制。它通过提供一种更优雅、更易于理解和管理的方式来处理异步操作,避免了回调地狱的问题。Promise的原理基于一种称为**“承诺”**的概念,表示某个操作的最终结果(可能是一个值或错误)

1.Promise的基本原理可以通过以下步骤来理解:

(1)创建Promise对象:
使用new Promise()来创建一个Promise对象,并传入一个执行器函数(executor function),该函数接受两个参数:resolve和reject。

(2)执行器函数的执行:
执行器函数会立即执行,并传递给它两个回调函数:resolve和reject。你可以在执行器函数中进行一些异步操作,当异步操作完成时,调用resolve函数来表示操作成功并传递结果,或调用reject函数来表示操作失败并传递错误信息。

(3)状态的改变:
Promise有三种可能的状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。当调用resolve函数时,Promise的状态会从pending变为fulfilled;当调用reject函数时,Promise的状态会从pending变为rejected。一旦Promise的状态改变,它就变为不可变的。

(4)处理结果:
可以通过Promise实例的then()方法来处理Promise的结果。then()方法接受两个参数:onFulfilled和onRejected,它们分别是在Promise成功或失败时被调用的回调函数。可以链式调用多个then()方法来处理多个异步操作。

2.一个简单的promise例子:

function asyncOperation() {
  return new Promise((resolve, reject) => {
    // 异步操作
    setTimeout(() => {
      const success = true;
      if (success) {
        resolve("Operation succeeded.");
      } else {
        reject("Operation failed.");
      }
    }, 1000);
  });
}

asyncOperation()
  .then((result) => {
    console.log(result); // 成功的结果
  })
  .catch((error) => {
    console.error(error); // 失败的错误信息
  });

在这个示例中,asyncOperation()函数返回一个Promise对象。当异步操作成功时,调用resolve()函数并传递结果;当异步操作失败时,调用reject()函数并传递错误信息。然后可以通过then()方法来处理成功的结果,或通过catch()方法来处理失败的情况。

需要注意的是,上述是一个简化的Promise实现示例,真正的Promise规范包含更多的细节和功能,例如Promise.all()、Promise.race()等方法,以及关于Promise链的处理等。

9.缓存用过吗,localStorage与sessionStorage的区别

1.介绍及对比:

LocalStorage和SessionStorage是HTML5中提供的两种用于在浏览器端存储数据的机制,它们在以下几个方面有所不同:

(1)数据生命周期:

LocalStorage:数据在浏览器中始终保留,除非显式删除或清除浏览器缓存。
SessionStorage:数据仅在当前会话期间有效。当用户关闭标签页或浏览器时,数据将被删除。

(2)作用域:

LocalStorage:数据在同源的所有标签页和窗口之间共享。
SessionStorage:数据仅在同一标签页或窗口中共享。

(3)存储大小限制:

LocalStorage:通常可以存储较大量的数据(通常为几MB)。
SessionStorage:存储大小较小(通常为几十KB到几MB),因为它的生命周期较短,不需要长时间保存大量数据。

(4)数据访问方式:

LocalStorage和SessionStorage都使用JavaScript的localStorage和sessionStorage对象进行访问。

使用setItem(key, value)方法可以将数据存储到LocalStorage或SessionStorage中。

使用getItem(key)方法可以从LocalStorage或SessionStorage中获取存储的数据。

使用removeItem(key)方法可以删除LocalStorage或SessionStorage中的特定数据。

使用clear()方法可以清空LocalStorage或SessionStorage中的所有数据。

根据你的需求,选择LocalStorage还是SessionStorage取决于你需要在会话期间共享数据还是需要在不同会话之间持久保存数据。

2.使用方式:

localtorage使用代码:

// localstorage使用
localStorage.setItem('key', 'value'); //存储数据
var value = localStorage.getItem('key'); //获取特定数据
console.log(value); // 输出存储的值
localStorage.removeItem('key'); //删除特定数据
localStorage.clear(); //清空所有数据

sessionstorage使用同localstorage类似,函数名和参数相同。

需要注意的是,存储的数据都是以字符串形式存储的。如果需要存储对象或其他数据类型,可以使用JSON.stringify()进行序列化,然后使用JSON.parse()进行反序列化。

10.let, const, var的区别

在 JavaScript 中,var、let 和 const 是用于声明变量的关键字,它们之间有以下区别:

1.作用域:

  • var 声明的变量具有函数作用域或全局作用域。在函数内部声明的变量只在函数内部有效,而在函数外部声明的变量则具有全局作用域。

  • let 和 const 声明的变量具有块级作用域。块级作用域可以是函数、循环、条件语句或任何使用花括号 {} 包裹的代码块。在块级作用域中声明的变量只在该块内部有效。

2.变量提升:

  • var 声明的变量存在变量提升的特性,即变量可以在声明之前使用。但是它的值会被默认初始化为 undefined。

  • let 和 const 声明的变量不会进行变量提升,即在声明之前使用会导致引用错误(ReferenceError)。

3.重复声明:

  • var 允许对同一个变量进行多次声明,而后续的声明会覆盖前面的声明。

  • let 和 const 不允许在同一个作用域内重复声明同一个变量,重复声明会导致语法错误(SyntaxError)。

4.可修改性:

  • var 和 let 声明的变量可以被重新赋值,即可以修改变量的值。

  • const 声明的变量被称为常量,其值在声明后不能被重新赋值,是只读的。但是对于复杂类型(如对象或数组),其内部的属性或元素仍可以被修改。

综上所述,let 和 const 是在 ES6 中引入的新的变量声明方式,相较于传统的 var,它们提供了更好的作用域控制、不进行变量提升和常量声明等特性,推荐在新的 JavaScript 代码中使用 let 和 const 来声明变量,而尽量避免使用 var。

11.怎么识别一个空对象{}

在 JavaScript 中,可以使用几种方式来判断一个对象是否为空对象(即不包含任何属性):

1.使用 Object.keys():

不能获取到不可枚举的属性,不能获取到继承自原型链上的属性。

const obj = {};
const isEmpty = Object.keys(obj).length === 0;
console.log(isEmpty); // 输出: true

2.使用 Object.getOwnPropertyNames():

能获取到不可枚举的属性
不能获取到原型链上的属性

const obj = {};
const isEmpty = Object.getOwnPropertyNames(obj).length === 0;
console.log(isEmpty); // 输出: true

3.使用 JSON.stringify():

只能获取自身的可枚举的属性。

const obj = {};
const isEmpty = JSON.stringify(obj) === '{}';
console.log(isEmpty); // 输出: true

4.使用 for…in 循环:

能获取到原型链上的属性。
不能获取到不可枚举的属性。

const obj = {};
let isEmpty = true;
for (let prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    isEmpty = false;
    break;
  }
}
console.log(isEmpty); // 输出: true

这些方法都可以判断一个对象是否为空对象。它们的原理是通过检查对象的属性数量或字符串化后的结果来确定是否为空。请注意,使用 for…in 循环时,需要通过 hasOwnProperty() 方法来判断属性是否是对象自身的属性,而不是继承自原型链的属性。,另外几种方法不会获取到原型链上的属性。

需要注意的是,如果对象的原型链上存在属性,即使对象本身没有属性,也不能被视为空对象。上述方法只能判断对象自身的属性是否为空。

12.谈谈对作用域,作用域链的理解

在前端的 JavaScript 中,作用域是指变量、函数和对象的可访问范围。作用域决定了在代码中何处可以访问到变量、函数和对象。JavaScript 中的作用域可以分为全局作用域和局部作用域。

1.全局作用域:

全局作用域是指在整个 JavaScript 程序中都可访问的作用域。在全局作用域中声明的变量和函数可以在程序的任何地方被访问。

2.函数作用域:

函数作用域是指在函数内部声明的变量和函数可以在函数内部访问,而在函数外部无法访问。每当你创建一个新的函数,就会创建一个新的函数作用域。函数参数也属于函数作用域中的变量。

3.块级作用域

块级作用域是指由一对花括号 {} 包裹的代码块所创建的作用域。在块级作用域中声明的变量只在该作用域内部有效,在作用域外部无法访问。

在 JavaScript 早期版本中,只有全局作用域和函数作用域,没有块级作用域。但自从 ES6(ECMAScript 2015)引入了 let 和 const 关键字,块级作用域成为了 JavaScript 的一部分。

4.作用域链

作用域链是 JavaScript 中与作用域相关的一个重要概念。当访问一个变量时,JavaScript 引擎会从当前作用域开始查找该变量,如果在当前作用域中找不到,则会沿着作用域链逐级向上查找,直到找到该变量或到达全局作用域。作用域链的顶端是全局作用域。

作用域链的构建是在函数定义的时候确定的,而不是在函数调用的时候。每个函数都会包含对其父级作用域的引用,这个引用被保存在内部的[[Scope]]属性中,用于在变量查找时构建作用域链。

当在函数内部访问一个变量时,JavaScript 引擎首先查找函数的局部作用域,如果找不到,则继续向上查找父级作用域,直到找到该变量或到达全局作用域。如果在所有的作用域中都找不到该变量,则会抛出 ReferenceError。

以下是一个示例,演示了作用域和作用域链的概念:

var globalVariable = 'Global'; // 全局作用域

function outer() {
  var outerVariable = 'Outer'; // outer 函数的局部作用域

  function inner() {
    var innerVariable = 'Inner'; // inner 函数的局部作用域

    console.log(innerVariable); // 可以访问 innerVariable
    console.log(outerVariable); // 可以访问 outerVariable
    console.log(globalVariable); // 可以访问 globalVariable
  }

  inner();
}

outer();

在这个示例中,globalVariable 是一个全局变量,在任何地方都可以访问。outer 函数有一个局部变量 outerVariable,在 outer 函数内部可以访问。inner 函数有一个局部变量 innerVariable,在 inner 函数内部可以访问。

当在 inner 函数中访问变量时,会先在当前作用域中查找,如果找不到则继续向上查找。因此,inner 函数可以访问到 innerVariable、outerVariable 和 globalVariable。

理解作用域和作用域链对于正确理解和编写 JavaScript 代码至关重要。它们帮助我们控制变量的可访问性和避免命名冲突,同时也影响着函数的执行环境和闭包的行为。

13.外部如何访问函数内部变量 闭包

在JavaScript中,闭包(Closure)是指函数及其相关的变量(环境)的组合。它允许函数访问在其词法作用域外部定义的变量。换句话说,闭包是指函数保留对它被创建时所处的词法作用域的引用,即使函数在该词法作用域外部执行也可以访问到其中的变量。

1.闭包的作用主要有以下几点:

  • 封装变量:闭包可以封装变量,将其隐藏在函数内部,只暴露特定的接口供外部访问,从而实现变量的私有化。

  • 保持状态:由于闭包保留了函数定义时的词法作用域,可以通过闭包在函数调用之间保持某些状态。每次调用函数时,闭包中的变量都可以保持之前调用时的值。

  • 实现函数内部的函数:闭包可以创建函数内部的函数,并让内部函数访问外部函数的变量。这种机制常用于实现模块化、函数工厂等模式。

实现闭包的关键是将函数定义在另一个函数内部,并将内部函数作为返回值或被传递给其他函数。通过这种方式,内部函数可以捕获外部函数的变量和参数,形成闭包。

以下是一个简单的闭包示例:

function outer() {
  var x = 10; // 外部函数的变量

  function inner() { // 内部函数
    console.log(x); // 内部函数访问外部函数的变量
  }

  return inner; // 返回内部函数
}

var closure = outer(); // 调用外部函数,返回内部函数
closure(); // 执行内部函数,输出: 10

在这个示例中,函数 outer 内部定义了变量 x 和内部函数 inner。inner 函数捕获了 outer 函数的变量 x,形成了闭包。通过将 inner 函数作为返回值,我们可以将闭包保存在变量 closure 中。每当调用 closure() 时,内部函数 inner 可以访问并打印外部函数 outer 中的变量 x 的值。这样就可以实现在外部访问函数内部变量。

需要注意的是,闭包会保留对外部函数中变量的引用,因此在使用闭包时要注意内存泄漏问题。如果闭包中引用了大量的变量或者变量占用的内存较大,但不再需要使用闭包时,应该及时释放对外部变量的引用,以避免不必要的内存消耗。

2.外部函数如何访问函数内部变量

在 JavaScript 中,外部通常无法直接访问函数内部的变量,因为函数内部的变量具有函数作用域,只能在函数内部访问。然而,可以通过一些机制来实现外部访问函数内部变量的需求。

一种常见的方法是使用闭包。闭包可以创建一个函数和其相关的词法环境的组合,从而使函数可以访问其词法作用域之外的变量。通过在函数内部返回内部函数,外部代码就可以通过调用内部函数来访问函数内部的变量。

以下是一个使用闭包实现外部访问函数内部变量的示例:

function outer() {
  var x = 10; // 内部变量

  function inner() {
    console.log(x); // 访问内部变量
  }

  return inner; // 返回内部函数
}

var closure = outer(); // 调用外部函数,返回内部函数
closure(); // 执行内部函数,输出: 10

在这个示例中,函数 outer 内部定义了变量 x 和内部函数 inner。通过将 inner 函数作为返回值,我们创建了一个闭包。外部代码通过调用闭包 closure 来执行内部函数 inner,从而访问并打印函数 outer 内部的变量 x 的值。

另一种方法是将需要外部访问的变量定义为全局变量。全局变量可以在整个代码中访问,包括函数内部。但是,使用全局变量可能会导致命名冲突和变量污染等问题,因此需要谨慎使用。

14.有没有用过Echart

15.用过什么组件库

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值