一份简单的前端开发指南


这篇博客是一份简单的前端开发指南,覆盖了从HTML基础到Vue框架的相关内容·。它分为六大部分,介绍了构建现代网页所需的各种技术和方法。开始于HTML的核心概念,如表格、标签种类及元素分类。接着深入CSS,讲述样式的应用、布局设计和视觉效果的实现。JavaScript部分探讨了编程语言的基础,包括变量声明、数据类型、函数使用等核心概念。ES6章节引入了新的语法特性和编程模式,为代码提供了更高效、简洁的实现方式。Vue部分则是专注于这一流行的前端框架。

一、HTML

HTML面试题:30道含答案和代码示例的练习题-CSDN博客

1、表格

table tr td

image-20240228131448198

2、常见标签

image-20240228131649413

ol 是 ordered list的缩写,表示有序列表。

ul 是 unordered list的缩写,表示无序列表。

HTML面试题整理-CSDN博客

如何在HTML中使用JavaScript?

<script src="example.js"></script>
3、行内、块级

image-20240228132330018

image-20240228132642230

行内元素上下不起作用

image-20240228132630959

4、行内块级元素

行内块级元素

详解块级元素、行内元素、行内块级元素类型、区别及相互转化-CSDN博客

image-20240228133811071

image-20240228133824191

image-20240228134046793

image-20240228134406780

为什么需要设置行内块级元素,因为div会导致独占一行,但是span不能设置高度

二、CSS

1、三种样式

css样式的三种位置 行内 内部 外部 优先级

  • 行内(内联)样式优先级高于内部和外部
  • 内部样式就是通过style标签包裹的样式,外部样式,通过link标签导入的样式的优先级相等,后面会覆盖前面的样式

image-20240228140135988

2、链接样式
  • rel="stylesheet"rel属性指定了当前文档和被链接资源之间的关系。在这个上下文中,rel="stylesheet"告诉浏览器被链接的资源是一个样式表,它应该被用来样式化当前的HTML文档。stylesheet的值表明这个链接的资源是用来定义文档的表现或者布局的CSS文件。
  • href="../CSS/css_02.css"href属性指定了被链接资源的URL(统一资源定位符)。在这个例子中,它指向一个名为css_02.css的CSS文件。路径../CSS/css_02.css表明这个CSS文件位于当前HTML文件所在目录的上一级目录中的CSS文件夹内。href的值是一个相对URL,它相对于当前文档的位置指定了资源的位置。

image-20240228135821750

3、浮动

【web前端开发】CSS浮动-CSDN博客

浮动会脱离标准流(俗称"脱标"),在标准流中不占位置

对元素设置浮动时,如果包含块没有设置高度或者高度是自适应的,此时浮动元素的高度就不会被计算进去

CSS清除浮动的多种方法 - Web前端工程师面试题讲解_哔哩哔哩_bilibili

image-20240228142555448

image-20240228142612963

image-20240228143317727

image-20240228144717775

当元素浮动父级的元素高度就会消失

三种方式

010-10分钟弄懂CSS属性float浮动和清除浮动的3个方法_哔哩哔哩_bilibili

image-20240228165454206

4、清除浮动

1、设置高度

2、overflow:hidden

3、伪元素

overflow: hidden 能够解决坍塌问题,主要是因为它影响了元素的块格式化上下文 (Block Formatting Context, BFC)。在CSS中,块格式化上下文是页面布局的一部分,它决定了元素如何对其内容进行布局,以及与其他元素之间的关系和交互。

当你将元素的 overflow 属性设置为 hidden 时,你实际上是为该元素创建了一个新的块格式化上下文。这个新的BFC具有几个重要特性,其中之一就是能够包含浮动元素(floats)。

解决坍塌问题的机制

当一个容器元素内部包含浮动元素时,如果没有启用新的BFC,容器将无法正确地包围或清除内部的浮动元素。这是因为浮动元素脱离了常规的文档流,而没有启用BFC的容器将不会自动调整其高度以包含浮动元素,导致所谓的“父级坍塌”。

通过设置 overflow: hidden(或其他值,如 scrollauto,也能触发BFC),容器就创建了自己的BFC,这意味着它将独立于外部环境对其内容进行布局。因此,该容器能够“看到”并正确地包围其内部的浮动元素,从而防止了高度坍塌的问题。

其他影响

  • 隔离浮动: 在新的BFC中,容器的边界将会包含浮动元素,防止它们溢出。
  • 防止外边距合并: 在同一个BFC中的相邻块级元素会发生外边距合并。通过创建新的BFC,可以阻止属于不同BFC的块级元素之间的外边距合并。

总结来说,overflow: hidden 解决坍塌问题的根本机制是通过创建新的块格式化上下文,这样使得容器能够正确地计算和包含其内部元素(包括浮动元素)的尺寸和位置,避免了布局问题。

5、伪类,伪元素

image-20240228165422784

6、position

50道CSS基础面试题(附答案)

50道CSS基础面试题(附答案)-CSDN博客

CSS定位position总结(超详细哦!)_css position-CSDN博客

image-20240228165925893

CSS系列之定位详解_css定位-CSDN博客

image-20240228171934992

image-20240228172435164

fixed 滚动条使用

7、后代选择器

CSS的.father>p.father span选择器用于应用样式,但它们的作用范围和目标元素有所不同:

  1. .father>p选择器:
    • 这个选择器针对所有直接子元素p(即段落)应用样式,这些p元素必须是.father元素的直接子元素。
    • 例如,如果有一个具有类名father的div元素,那么这个选择器将只会影响直接嵌套在这个div元素内的p元素。
    • 设置的background-color: lightcoral;样式会将所有这些直接子p元素的背景颜色设置为浅珊瑚色。
  2. .father span选择器:
    • 这个选择器针对所有在.father内的span元素应用样式,无论这些span元素是直接还是间接嵌套在.father内。
    • 这意味着,不论span元素位于何处,只要它们在.father元素的任何层级内部,都会被选中并应用样式。
    • 设置的样式(display: block; width: 100%; background-color: lightsalmon;)会使所有这些span元素表现为块级元素,宽度扩展到100%,并将背景颜色设置为浅鲑鱼色。

总结差异:

  • 选择器范围.father>p只选择.father的直接子p元素,而.father span选择.father内的所有span元素,不论它们的嵌套深度。
  • 目标元素.father>p专门针对p元素,.father span则针对span元素。
  • 样式应用:两者的样式不同,前者改变背景颜色,后者除了改变背景色外,还改变了显示方式和宽度。
8、弹性布局

flex布局(弹性布局)-CSDN博客

flex布局(弹性布局)

image-20240228174535688

image-20240228174544720

image-20240228174551686

image-20240228174556667

image-20240228174600006

image-20240228174608368

【前端经典】flex弹性布局,flex布局,flex布局用法,网页设计与制作,前端开发。_哔哩哔哩_bilibili

【前端经典】flex弹性布局,flex布局,flex布局用法,网页设计与制作,前端开发。

image-20240228174426312

三、JavaScripts

1、null和undefined的区别

两个数据类型都是基本数据类型,并且都有一个值,null和undefined。

undefined的意思是未定义,比如说只是声明了一个变量但是为定义,那么就是undefined,

null是一个空对象。

image-20240228210408424

  • undefined表示变量已被声明但尚未被赋值。
  • null是一个赋给变量的值,用以表示变量的值为空。

image-20240229104245274

2、var let const

一文了解let、const与var的区别 (baidu.com)

image-20240228225835062

  • let用于声明变量,用法与var类似
  • const用于声明常量:

在JavaScript中,varlet都用于变量声明,但它们在行为上有明显的不同,特别是关于变量提升(hoisting)和作用域。了解这些差异对于编写可预测和易于维护的代码至关重要。

变量提升(Hoisting)

  • var: 使用var关键字声明的变量会被提升到其所在函数或全局作用域的顶部。这意味着无论变量在哪里声明,都好像它被声明在了作用域的最开始处。然而,只有声明本身被提升,初始化赋值不会被提升。
  • let: 使用let关键字声明的变量不会被提升。如果在声明之前访问它,JavaScript会抛出一个ReferenceError错误,表明变量尚未被声明。

带来的问题

  1. 意外的行为: 由于var声明的变量被提升,代码可能会表现出开发者没有预期的行为。特别是在大型函数中,变量在声明之前就可以访问,可能导致混乱和错误。
  2. 重复声明: 使用var可以在同一个作用域中多次声明同一个变量,而不会引发错误。这可能导致代码调试困难,因为最新的声明会覆盖之前的声明。
  3. 作用域问题: var声明的变量是函数作用域或全局作用域的,而let声明的变量是块作用域的。这意味着使用var可能会无意中创建全局变量,或者在for循环等场景下不符合预期地共享变量。

示例

变量提升的例子:

console.log(a); // undefined, 而不是ReferenceError
var a = 5;

console.log(b); // ReferenceError: b is not defined
let b = 5;

作用域问题的例子:

for (var i = 0; i < 5; i++) {
  // ...
}
console.log(i); // 5,`i`泄漏到了循环外部

for (let j = 0; j < 5; j++) {
  // ...
}
console.log(j); // ReferenceError: j is not defined,`j`仅在循环内部有效

重复声明的例子:

var c = 1;
var c = 2; // 有效,不会报错
console.log(c); // 2

let d = 1;
let d = 2; // SyntaxError: Identifier 'd' has already been declared

总的来说,letconst(常量声明,类似于let,但赋值后不能改变)提供了更加精确的作用域控制和更少的意外行为,是现代JavaScript代码中推荐的声明方式。

const虽然是常量但是也可以表示数组,因为地址不改变

在JavaScript中,varletconst都用于声明变量,但它们在作用域(scope)、提升(hoisting)、以及可重新赋值方面有所不同。

var

  • 作用域var声明的变量拥有函数作用域(function scope),在整个函数内都可见,包括函数的所有代码块(例如if语句和循环)。如果在函数外声明,var声明的变量拥有全局作用域。
  • 提升var声明的变量会被提升到其作用域的顶部,但只是提升声明而不初始化。这意味着在变量声明之前就可以访问它,但访问的结果是undefined
  • 可重新赋值:可以随时更改var声明的变量的值。

let

  • 作用域let声明的变量拥有块级作用域(block scope),即只在它声明的代码块(如if语句、循环、或任意{}中)内可见。
  • 提升let声明的变量也会提升到其作用域的顶部,但不会像var那样初始化。在声明之前访问let变量会导致ReferenceError。这种现象被称为“暂时性死区”(Temporal Dead Zone,TDZ)。
  • 可重新赋值:可以随时更改let声明的变量的值。

const

  • 作用域const声明的变量也拥有块级作用域,和let一样。
  • 提升const声明的变量也会提升,但与let相同,存在于“暂时性死区”,在声明之前不能访问。
  • 可重新赋值const声明的变量不能重新赋值。它用于声明一个只读的常量。但如果这个常量是一个对象或数组,对象的属性或数组的元素可以被修改。

总结

  • var提供函数作用域或全局作用域,且变量可以被重新声明和修改。
  • letconst提供块级作用域,更加严格,有助于避免代码中的错误。
  • let允许变量重新赋值,而const不允许。使用const可以声明不希望被重新赋值的常量。
3、原生数据类型

【javaScript面试题】2023前端最新版javaScript模块,高频24问_js面试题2023-CSDN博客

String Number Boolean null undefined

USB NN

没有浮点数的概念,都是Number类型

1.js的数据类型

数据类型分为两种:基本数据类型与引用数据类型。基本数据类型有:number、string、boolean、null、undefined。引用数据类型有:array、function等(除了基本数据类型都是引用数据类型)

基本数据类型的主要特点是赋值方式是传值,并且值存在栈中。

引用数据类型的主要特点是赋值方式是传址,并且值存在堆中。

栈(stack)会自动分配内存空间,会自动释放。堆(heap)动态分配的内存,大小不定也不会自动释放。

4、双等和三等

双等主要是值类型进行比较,三等是值类型与数据类型进行双层比较。

简单来说就是三等因为传递的是地址,因此我们需要先对比数据类型,再看地址内部存储的数据是否相等。而双等仅仅是看值是否相等,值相等即可无需比较类型。

5、箭头函数

写法不同。箭头函数更加专注于结果写法由于()=>{}构成,写法简洁

this指向不同。箭头函数中 this 的指向不同:在普通函数中,this 总是指向调用它的对象,如果用作构造函数,它指向创建的对象实例。箭头函数中没有this,箭头函数的this指向取决于外层作用域中的this,外层作用域或函数的this指向谁,箭头函数中的this便指向谁。

6、闭包

闭包:就是能够读取外层函数内部变量的函数。

闭包需要满足三个条件:

访问所在作用域;

函数嵌套;

在所在作用域外被调用 。

优点: 可以重复使用变量,并且不会造成变量污染 。

缺点: 会引起内存泄漏

使用闭包的注意点:

由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象

(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

7、逗号和分号

在JavaScript中,逗号(,)和分号(;)用于不同的语法结构中,它们的使用规则如下:

分号(;

语句分隔符:在JavaScript中,分号用作语句的结束标记。它用于分隔连续的语句,这在将多个语句写在同一行时特别有用。虽然在许多情况下,JavaScript引擎能够在缺少分号的地方自动推断出语句的结束(称为自动分号插入,ASI),但明确使用分号可以避免误解和错误。

let a = 1; // 分号标记语句结束
let b = 2; // 另一个语句,同样以分号结束

循环、条件语句等不需要分号:在控制流语句(如ifforwhile等)的声明块结束时,不需要分号。

if (a === b) {
  console.log("Equal");
} // if语句结束后不需要分号

逗号(,

分隔列表项:逗号用于分隔数组、对象或函数参数列表中的项。

let arr = [1, 2, 3]; // 分隔数组项
let obj = { id: 1, name: "John" }; // 分隔对象属性
function sum(a, b, c) { return a + b + c; } // 分隔函数参数

变量声明:在使用一个letconstvar声明多个变量时,逗号用于分隔变量。

let x = 1, y = 2, z = 3; // 使用逗号分隔变量声明

四、ES6

image-20240229103827414

1、symbol

Symbol 在 JavaScript 中是一种基本数据类型,用于创建一个唯一的标识符。Symbols 主要用于对象属性的键,以保证不会与其他属性键发生冲突。以下是 Symbol 的一些基本使用方法:

创建 Symbol

你可以使用 Symbol() 函数创建一个新的 Symbol。每次调用都会创建一个独一无二的 Symbol。

let symbol1 = Symbol();
let symbol2 = Symbol('description'); // 带有可选描述

Symbol 的描述

当你创建一个 Symbol 时,可以提供一个字符串作为其描述,这在调试时很有用。但是,这个描述并不影响 Symbol 的唯一性。

let symbol = Symbol('这是一个描述');
console.log(symbol.toString()); // "Symbol(这是一个描述)"

使用 Symbol 作为对象属性键

Symbol 可以用作对象属性的键,这样可以保证属性不会与其他属性键冲突,即使它们有相同的名称也不会。

let id = Symbol('id');
let person = {
    name: '张三',
    [id]: 123 // 使用 Symbol 作为属性键
};

console.log(person[id]); // 123

Symbols 是唯一的

即使两个 Symbols 有相同的描述,它们也是不同的。

let symbol1 = Symbol('id');
let symbol2 = Symbol('id');
console.log(symbol1 == symbol2); // false

Symbol.for 和 Symbol.keyFor

  • Symbol.for(key):根据给定的键 key 搜索已存在的 Symbols,如果找到则返回它。如果没有找到,会创建一个新的 Symbol。
  • Symbol.keyFor(symbol):接受一个 Symbol,返回一个已登记的 Symbol 的键。如果 Symbol 未被登记,返回 undefined
let symbol1 = Symbol.for('id'); // 如果不存在,则创建一个新的 Symbol
let symbol2 = Symbol.for('id'); // 从全局 Symbol 注册表中搜索并返回

console.log(symbol1 === symbol2); // true

let key = Symbol.keyFor(symbol1);
console.log(key); // "id"

Symbol 属性不会出现在 for…in 循环中

使用 Symbol 作为对象属性键的属性不会出现在 for...in 循环中。同样,Object.keys()Object.getOwnPropertyNames() 也不会返回 Symbol 属性。但是,你可以使用 Object.getOwnPropertySymbols() 方法获取对象中的所有 Symbol 属性。

let id = Symbol('id');
let person = {
    name: '张三',
    [id]: 123
};

console.log(Object.keys(person)); // ["name"]
console.log(Object.getOwnPropertySymbols(person)); // [Symbol(id)]

这些是 Symbol 类型的基本使用方法,它在创建独一无二的标识符时非常有用,尤其是在处理大型代码库或库与应用程序之间的交互时,可以有效避免名称冲突的问题。

2、for 和 forEach 的区别 ?

1.for循环可以使用break跳出循环,但forEach不能。

2.for循环可以控制循环起点(i初始化的数字决定循环的起点),forEach只能默认从索引0开始。

3.for循环过程中支持修改索引(修改 i),但forEach做不到(底层控制index自增,无法左右它)。

3、this问题

image-20240229104019015

4、cookie, local、sessionStorage

cookie

存储方式:

存储用户信息,获取数据需要与服务器建立连接。

以路径存储,上层路径不能访问下层的路径cookie,下层的路径cookie可以访问上层的路径cookie

作用与特性:

可存储的数据有限,且依赖于服务器,无需请求服务器的数据尽量不要存放在cookie 中,以免影响页面性能。

可设置过期时间。

存储数量及大小:

将cookie控制在4095B以内,超出的数据会被忽略。

IE6或更低版本 最多存20个cookie;

IE7及以上

版本 多可以有50个;

Firefox多 50个;

chrome和Safari没有做硬性限制。

cookie最大特征就是可以在页面与服务器间互相传递,当发送或者接受数据时自动传递
localStorage

存储客户端信息,无需请求服务器。

数据永久保存,除非用户手动清理客户端缓存。

开发者可自行封装一个方法,设置失效时间。 5M左右,各浏览器的存储空间有差异。

任何地方都可以存都可以取

操作简单
sessionStorage

存储客户端信息,无需请求服务器。

数据保存在当前会话,刷新页面数据不会被清除,结束会话(关闭浏览器、关闭页面、跳转页面)数据失效。

5M左右,各浏览器的存储空间有差异。

同页面不同窗口中数据不会共享

5、函数的节流和防抖 ?

它们虽然目的相同——限制函数在特定时间内的调用次数,但实现方式和适用场景有所不同。

节流 ----控制流量,规定时间操作规定次数

防抖----触发一段时间后在继续计时,如果其中又有时间触发,重新计时

函数的节流(Throttling)和防抖(Debouncing)都是优化高频率执行代码的技术手段,尤其在处理诸如窗口缩放、页面滚动、表单验证和自动完成等事件时非常有用。它们虽然目的相同——限制函数在特定时间内的调用次数,但实现方式和适用场景有所不同。

防抖(Debouncing)

防抖的核心思想是在事件被触发一段时间后才执行,如果在这段时间内事件又被触发,则重新计时。这意味着,只有当事件停止触发一段时间后,事件处理函数才会执行一次。防抖通常用于输入框连续输入的场景,确保只有在用户停止输入后才进行输入验证或其他操作。

节流(Throttling)

节流的策略略有不同,它保证一个函数在一定时间内只执行一次,不管事件触发了多少次。即使在这段时间内事件被触发多次,事件处理函数也只会按照设定的时间间隔被调用一次。节流常用于限制执行频率较高的操作,如窗口的滚动、浏览器的缩放等。

区别总结

  • 触发频率:防抖在连续的事件触发中不执行,直到事件停止触发后的一段时间才执行一次;节流则是按照固定的时间间隔执行,不管事件触发了多少次。

  • 适用场景

    • 防抖适用于触发频率高,但只关心最后一次触发结果的场景(如输入验证)。
    • 节流适用于触发频率高,且需要在事件触发期间定时执行的场景(如滚动事件的处理)。

理解这两种技术的区别和适用场景,可以帮助你在不同的开发场景中做出更合适的选择,从而优化性能和用户体验。

6、promise

Promise 是异步编程的一种解决方案:从语法上讲,promise是一个对象,从它可以获取异步操作的消息;

从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。

promise有三种状态: pending(等待态),fulfilled(成功态),rejected(失败态);状态一旦改变,就不会再变。创造promise实例后,它会立即执行

promise是用来解决两个问题的:

回调地狱,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象

promise可以支持多个并发的请求,获取并发请求中的数据

这个promise可以解决异步的问题,本身不能说promise是异步的

7、new一个对象的过程

在JavaScript中,new关键字用于创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。当你使用new操作符来创建一个新对象时,实际上会经历以下四个步骤:

  1. 创建一个新对象new关键字首先会创建一个空的JavaScript对象({})。
  2. 继承构造函数的原型链:接着,这个新对象内部的[[Prototype]](也就是__proto__属性,现代JavaScript中使用Object.getPrototypeOf()Object.setPrototypeOf()来访问)会被赋值为构造函数的prototype属性。这样新对象就可以访问构造函数原型上定义的属性和方法。
  3. 将构造函数的this指向这个新对象:这意味着在构造函数中使用this关键字时,它会指向新创建的对象,允许我们向新对象添加属性和方法。
  4. 返回这个新对象:如果构造函数没有显式返回一个对象,则会默认返回新创建的对象。如果构造函数返回的是一个非对象类型(如数值、字符串或布尔值),那么这个返回值会被忽略,而new操作符调用的结果仍然是新创建的对象。如果构造函数返回的是一个对象,则该对象会成为new操作符的返回值。

这个过程允许JavaScript中的函数通过new关键字充当构造函数,用于创建新对象,并且这些对象自动继承构造函数原型上的属性和方法,实现了基于原型的继承。

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.sayHello = function() {
  console.log("Hello, my name is " + this.name + " and I am " + this.age + " years old.");
};

var person1 = new Person('John', 30);
person1.sayHello(); // 输出: Hello, my name is John and I am 30 years old.
8、原型和原型链

【前端八股文】原型和原型链_哔哩哔哩_bilibili

Object.getPrototypeOf(obj)

image-20240229194713597

image-20240229194845565

image-20240229204531699

9、for in 和for of 区别

for in 用于遍历对象的键(key),for in会遍历所有自身的和原型链上的可枚举属性。如果是数组,

for in会将数组的索引(index)当做对象的key来遍历,其他的object也是一样的。

for ofes6引入的语法,用于遍历 所有迭代器iterator,其中包括HTMLCollection,NodeList,ArrayMapSetStringTypedArrayarguments

对象的值(item)。

image-20240229111015553

image-20240229111214257

10、for forEach Map

在JavaScript中,变量类型是动态的,这意味着你不需要(也不能)在声明变量时指定数据类型。JavaScript是一种动态类型语言,变量的类型是在运行时根据其当前值自动确定的。因此,当你使用如forEach方法的回调函数时,参数(如element)的类型是由函数调用时传入的实际数据决定的。

在JavaScript中,for循环、forEach方法和map方法都可以用来遍历数组,但它们各有特点和适用场景。

for循环

for循环是最基本的循环结构,提供了最高的灵活性。它可以用于遍历数组、对象的属性以及其他自定义迭代需求。

示例:

const array = ['a', 'b', 'c'];
for (let i = 0; i < array.length; i++) {
  console.log(array[i]);
}
// 输出:
// a
// b
// c

forEach方法

forEach是Array的原型方法,用于遍历数组。它为数组中的每个元素执行一次提供的函数。注意,forEach不能被中断,要想提前退出循环,只能通过抛出异常等方式。

示例:

const array = ['a', 'b', 'c'];
array.forEach(function(element) {
  console.log(element);
});
// 输出:
// a
// b
// c

map方法

map同样是Array的原型方法,它通过对每个数组元素调用一个函数来创建一个新数组。map用于当你想生成一个与原数组对应的新数组时,非常适用。

示例:

const array = [1, 2, 3];
const squaredArray = array.map(function(element) {
  return element * element;
});
console.log(squaredArray);
// 输出:
// [1, 4, 9]

这个问题的关键是在js中函数名是可以通过参数传递的

区别和联系

  • 使用场景
    • for循环:当需要最大程度的控制循环过程时使用,比如可以中途跳出循环。
    • forEach:适用于遍历数组进行操作,但不需要返回值,且不能中途跳出循环。
    • map:适用于将数组中的每个元素映射到一个新的元素上,生成一个新的数组。
  • 能否中断
    • for循环可以使用break语句中断。
    • forEach不能中途中断,除非抛出异常。
    • map同样不能中途中断,它总是返回一个新数组。
  • 返回值
    • for循环没有返回值。
    • forEach没有返回值。
    • map返回一个新数组,不改变原数组。

这三种方法各有优势,选择哪一种取决于具体的使用场景和需求。

array.forEach(function (element){
    console.log(element)
});

const new_array=array.map(function (element){
    return element*element
});
console.log(new_array)
11、回调函数

image-20240301132157839

在js中什么是回调函数_哔哩哔哩_bilibili

12、构造函数

【JS知识分享】什么是构造函数呢?_哔哩哔哩_bilibili

image-20240229195140443

image-20240229202328328

具体来说,这个过程可以分为以下几个步骤:

  1. 创建新对象:JavaScript首先创建一个空的对象。
  2. 设置原型:然后将这个新对象的内部[[Prototype]]属性(即它的原型)设置为构造函数的prototype属性。这样做是为了确保新对象可以访问构造函数原型上定义的属性和方法。
  3. 执行构造函数:接下来,JavaScript会以新创建的对象作为this的上下文来执行构造函数。在构造函数内部,可以通过this来为新对象添加属性和方法。在这个例子中,Person构造函数接受两个参数("Alice"30),并将它们分别赋值给新对象的nameage属性。
  4. 返回新对象:最后,如果构造函数没有显式返回一个对象,则JavaScript会自动返回这个新创建的对象。

因此,new Person("Alice", 30);这段代码实现了上述所有步骤,创建了一个Person类型的新对象实例,这个实例具有nameage属性。

var person1 = new Person("Alice", 30);这行代码不仅包含了实例化的过程,还包括了将新创建的对象实例赋值给变量person1的过程。这里,var person1是声明(或定义)一个变量,然后new Person("Alice", 30)实例化一个新的Person对象,最后这个新创建的Person实例被赋值给变量person1。因此,person1变量之后就可以用来引用和操作这个新创建的Person对象实例。

【前端八股文】原型和原型链_哔哩哔哩_bilibili

image-20240229203914391

image-20240229205014642

13、实例化

【JS知识分享】什么是构造函数呢?_哔哩哔哩_bilibili

在Fun()中的this指定是Windows

在obj1的构造函数就是 调用的内容

image-20240229195241807

14、原生对象
  1. 原生对象(Native Objects):

    • 基本对象

      • Object: 所有对象的基类。
      • Function: 所有函数的基类。
      • Boolean: 布尔值的构造函数。
      • Symbol: 符号的构造函数,用于创建唯一的标识符。
      • Error: 错误对象的构造函数,包括EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError等。
    • 数字和日期对象

      :

      • Number: 数字的构造函数。
      • Math: 提供数学运算的静态方法和属性。
      • Date: 日期和时间的构造函数。
    • 文本处理对象

      :

      • String: 字符串的构造函数。
      • RegExp: 正则表达式的构造函数。
    • 索引集合对象

      :

      • Array: 数组的构造函数。
      • Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array: 类型化数组,用于处理二进制数据。
    • 使用键的集合对象

      :

      • Map: 键值对集合,其中的键可以是任意类型。
      • Set: 值的集合,其中每个值只能出现一次。
      • WeakMap: 类似于Map,但是它仅接受对象作为键,且不阻止垃圾回收器回收其键指向的对象。
      • WeakSet: 类似于Set,但是成员只能是对象,且不阻止垃圾回收器回收其成员。
  2. 宿主对象(Host Objects):

    • 这些对象由JavaScript的运行环境提供,而不是由JavaScript语言本身定义的。
    • 在浏览器环境中,宿主对象包括window, document, location, history, XMLHttpRequest等,用于浏览器交互和页面操作。
    • 在Node.js环境中,宿主对象包括global, process, Buffer等,用于服务器端操作。
  3. 用户定义的对象:

    • 通过对象字面量、构造函数或类定义创建的对象。
15、箭头函数

js 箭头函数详解_js箭头函数-CSDN博客

// 普通函数
let sum = function(a, b) {
	return a + b;
}

// 箭头函数
let sum1 = (a, b) => {
	return a + b;
}
// 有效
let sum = (x) => {
	return x;
};
// 有效
let sum1 = x => {
	return x;
};
// 没有参数需要括号
let sum2 = () => {
	return 1;
};
// 有多个参数需要括号
let sum3 = (a, b) => {
	return a + b;
};

// 有效
let sum = (a, b) => {
	return a + b;
};
// 有效
let sum1 = (a, b) => a + b; // 相当于 return a + b;
// 无效的写法
let sum2 = (a, b) => return a + b;

在ES6(ECMAScript 2015)中,箭头函数是一种使用新的语法定义函数的方式,它提供了一种更简洁的函数写法。箭头函数特别适用于那些不需要自己的thisargumentssupernew.target的函数,并且它们不能用作构造函数。

箭头函数的语法特点如下:

  1. 更简洁的函数体:如果箭头函数的函数体只包含一个表达式,那么该函数会隐式返回这个表达式的值,无需使用return关键字。如果函数体包含多个表达式,则需要用花括号{}包围,并且需要使用return关键字来返回值(如果需要返回值的话)。
  2. 没有自己的this:箭头函数不创建自己的this上下文,因此this的值是在定义时继承自外层执行上下文。这使得箭头函数特别适合用作回调函数,避免了传统函数中this的动态变化问题。
  3. 不可当作构造函数:箭头函数不能用作构造函数,即不能使用new关键字调用箭头函数。如果尝试这样做,JavaScript会抛出一个错误。
  4. 没有arguments对象:箭头函数内部没有arguments对象。如果要访问函数的参数列表,可以使用剩余参数语法。
  5. 没有supernew.target绑定:箭头函数不能用作构造函数,因此它们也没有supernew.target

基本语法示例

  • 单个参数和单个表达式(隐式返回值):
const square = x => x * x;

无参数或多个参数时需要使用括号()

const sayHello = () => console.log('Hello!');
const add = (a, b) => a + b;

函数体包含多个表达式(需要显式返回值):

const multiplyAndLog = (a, b) => {
  console.log(a, b);
  return a * b;
};

箭头函数因其简洁性和处理this行为的方式而被广泛使用,尤其是在需要定义简短的函数或回调函数时。

当我们谈论箭头函数和this的指向时,关键在于箭头函数不绑定自己的this,它继承了它被创建时所处上下文的this值。换句话说,箭头函数内部的this值是在它被定义的时候确定的,而不是在它被调用的时候。

让我们通过一个更简单的例子来理解这个概念:

javascript
let num = 10;
const obj = {
    num: 20,
    fn: () => {
        console.log(this.num);
    }
};

obj.fn();

在这个例子中,fn是一个箭头函数。因为箭头函数不绑定自己的this,它所引用的this.num不是obj对象内部的num属性,而是箭头函数定义时的上下文中的this。如果这段代码是在全局作用域下执行的,那么this指向的是全局对象(在浏览器中是window,在Node.js中是global)。因此,如果全局作用域中有一个名为num的变量,那么this.num将引用那个变量。如果全局作用域中没有num变量,那么this.num将是undefined

但是,如果你将这段代码放在一个严格模式('use strict')的环境下执行,全局上下文中的this将是undefined,因为严格模式不允许this指向全局对象。在这种情况下,尝试访问this.num将会导致一个错误,因为undefined没有属性。

16、函数定义
  1. 函数声明(Function Declaration)

这是一种传统的定义函数的方式,ES6之前就已存在,但在ES6中依然有效。

function myFunction(a, b) {
    return a + b;
}
  1. 函数表达式(Function Expression)

函数也可以通过函数表达式的方式定义。这包括匿名函数表达式和命名函数表达式。

// 匿名函数表达式
const myFunction = function(a, b) {
    return a + b;
};

// 命名函数表达式
const myFunction = function sum(a, b) {
    return a + b;
};
  1. 箭头函数(Arrow Function)

ES6引入了箭头函数,提供了一种更简洁的方式来写函数。箭头函数特别适合用在匿名函数表达式中,例如回调函数。

const myFunction = (a, b) => {
    return a + b;
};

// 如果函数体只包含一个表达式,可以省略花括号和return关键字
const myFunction = (a, b) => a + b;

// 如果只有一个参数,可以省略参数周围的括号
const square = x => x * x;
  1. 默认参数值

ES6允许在定义函数的参数时为其指定默认值,如果调用时未提供值,则使用默认值。

function myFunction(a, b = 1) {
    return a + b;
}
  1. 剩余参数(Rest Parameters)

使用剩余参数语法,可以将一个不定数量的参数表示为一个数组。

function myFunction(a, ...rest) {
    console.log(a); // 第一个参数
    console.log(rest); // 除第一个参数外的其余参数组成的数组
}
  1. 解构赋值参数

在函数参数中使用解构赋值可以直接从对象或数组中提取值。

// 对象解构
function myFunction({a, b}) {
    return a + b;
}

// 数组解构
function myFunction([a, b]) {
    return a + b;
}

这些是ES6中定义函数的一些主要方式,每种方式根据不同的使用场景和需求选择最合适的。

五、vue

1、双向绑定/数据代理/数据劫持的原理

数据劫持(数据代理)

  • 数据劫持是通过某些JavaScript特性(如ES6的Proxy或ES5的Object.defineProperty)来监听数据对象的属性变化的过程。
  • 当这些属性发生变化时(比如赋了一个新值),可以捕获这些变化,并执行相应的逻辑(比如更新视图)。
2、mvvm的理解

是model-view-viewmodel的缩写,是一种结构模式(设计思想)
model是数据模型,用于对数据的定义和修改等操作。
view是ui视图层,用于渲染页面。
viewModel:负责监听model中数据的改变并控制属兔更新,处理用户交互操作。
修改View层,Model对应数据发生变化
Model数据变化,不需要查找DOM,直接更新View

MVVM(Model-View-ViewModel)是一种软件架构设计模式,它主要用于简化用户界面的开发。这种模式通过分离关注点来增强代码的可维护性和测试性,特别是在现代Web应用和各种桌面应用中非常流行。MVVM主要包括三个核心组件:Model(模型)、View(视图)和ViewModel(视图模型)。下面是对这三个组件的详细解释以及它们之间的交互方式:

Model(模型)

  • Model代表应用程序的数据逻辑。它直接管理数据、逻辑和规则,通常包括一个或多个数据源的表示,以及与这些数据相关的操作和处理逻辑。Model是独立于UI的,它不包含任何与视图显示相关的信息。

View(视图)

  • View是用户界面的表示。在Web应用中,它通常由HTML/CSS构成,负责展示数据(由ViewModel提供)给用户,并定义了用户界面的结构、布局和外观。View是被动的,它不直接修改Model,只是从ViewModel接收数据。

ViewModel(视图模型)

  • ViewModel是Model和View之间的连接器。它负责处理视图的逻辑,将Model的数据转换为View可以展示的形式,并反过来响应用户的输入,将其转化为Model的命令。ViewModel通过数据绑定(Data Binding)来实现View和Model之间的自动同步,这意味着当数据发生变化时,UI元素会自动更新,反之亦然。

数据绑定和数据同步

  • 数据绑定是MVVM模式的核心。通过数据绑定,ViewModel中的数据变化可以自动反映在View上,用户在View上的操作也可以自动更新到ViewModel和Model,这样开发者就不需要手动操作DOM来更新UI,或是直接操作数据模型来响应UI事件。
  • 数据同步是指当Model的状态改变时,ViewModel会感知到这些变化,并将新的状态反映到View上;同样地,当用户在View上进行操作时(如输入文本、点击按钮等),ViewModel也会更新Model的状态,从而实现Model和View的双向同步。

MVVM的优势

  • 提高可维护性:通过分离Model、View和ViewModel,开发者可以独立地工作在应用的不同部分上,降低了代码的耦合度。
  • 增强测试性:由于ViewModel与View的分离,可以在不依赖UI的情况下测试业务逻辑。
  • 简化UI开发:数据绑定减少了手动更新UI元素的需求,使得UI开发变得更加简单和高效。

MVVM模式通过其独特的结构提供了一个高度模块化和可测试的应用架构,特别适合复杂的前端应用开发。

MVVM 是 Model-View-ViewModel 的缩写。 Model代表数据模型,也可以在 Model中定义数据修改和操作的业务逻辑。 View 代表UI 组件,它负责将数据模型转化成 UI 展现出来。 ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理 解就是一个同步View 和 Model的对象,连接Model和View。 在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也 会立即反应到View 上。 ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起 来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关 注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维 护完全由 MVVM 来统一管理。

3、计算属性和监听属性

计算属性:
-get、set属性,底层借助了object.defineproperty方法提供的getter和setter。
-当读取计算属性里的值时,get会被调用,初次读取值或者所依赖的数据发生改变时都会被调用。
-有缓存,只有所依赖的数据发生改变时缓存的值才会更新。
-当计算属性的值被直接修改时会执行set
监听属性
-当监视属性变化时,回调函数自动调用,进行相关操作。
-监听属性有两种写法:new Vue里传入watch配置或者通过vm.$watch()监听。
-有handler函数,其身上有旧值与新值(newValue,oldValue)
-没有缓存
-检测data里的属性,也可以监听计算属性里的值
-默认不检测对象内部值的改变,可配置deep:true开启深度监听

计算属性(Computed Properties)和侦听器(Watchers)是现代前端框架中常用的两种响应式特性,它们在处理数据变化时各有优势。理解它们之间的区别,尤其是为什么计算属性有缓存而侦听器没有,可以帮助你更有效地使用这些特性。

计算属性(Computed Properties)

计算属性是基于它们的响应式依赖进行缓存的。只有当依赖项发生变化时,计算属性才会重新计算。这意味着,如果依赖项没有发生变化,无论你访问计算属性多少次,都会立即返回最后计算的结果,而不需要再次执行计算逻辑。这种缓存机制使得计算属性非常高效,特别是当计算成本较高或依赖于多个源数据时。

优点:

  • 性能优化:避免了不必要的计算,特别是对于复杂计算而言。
  • 数据派生:适用于需要从现有数据派生出新数据的场景。

侦听器(Watchers)

侦听器允许你执行任何逻辑响应数据的变化,当你需要在数据变化时执行异步操作或较为复杂的逻辑时,侦听器非常有用。与计算属性不同,侦听器不会缓存数据。它们每次在侦听的数据变化时都会执行定义的回调函数。

缺点:

  • 没有缓存:每次数据变化都会执行,可能会导致性能问题,尤其是当执行昂贵的操作时。

为什么这样设计?

  • 计算属性的缓存机制是为了优化性能。在多数情况下,计算属性用于同步操作,依赖于其他数据,并且这些操作不需要每次数据访问时都重新执行。缓存机制确保了只有在必要时才重新计算,从而提高应用性能。
  • 侦听器不缓存是因为它们通常用于执行数据变化的响应操作,如异步API调用、长时间运行的任务等。这些操作需要在每次数据变化时执行,因此不适合使用缓存。

总结

  • 使用计算属性来处理那些依赖于响应式数据变化的同步操作,特别是当这些操作需要数据派生或有重复计算时。
  • 使用侦听器来处理异步操作或那些需要在数据变化时执行的较为复杂的逻辑。

理解计算属性和侦听器的这些关键差异,可以帮助你更合理地在应用中使用它们,优化应用性能并提升开发效率。

-computed:是计算函数,注重计算出来的值,所以必须写返回值
-watchEffect:是监视函数,注重过程,不用写返回值

4、v-if和v-show的区别

-v-show是通过dispaly的属性值来控制元素的显示与隐藏,隐藏后dom元素节点还存在。
-v-if则是通过元素节点的创建与销毁来实现元素的显示与隐藏,隐藏后dom元素节点不存在。
-v-show适用于切换频率比较频繁的场景。
-v-if适用于切换频率比较低的场景。

5、vue生命周期

Vue生命周期总结(四个阶段,八个钩子函数)-CSDN博客

beforeCreate:实例创建之前,初始化事件和数据,无法访问data中的数据和methods中的方法。数据代理未开始
created:实例创建完成,数据和事件已初始化完成,可以访问到data中的数据和methods里的方法。数据监测、数据代理
beforeMounte:实例挂在之前,虚拟dom以准备好,还没有生成真实dom,页面还没有被渲染,对所有的dom操作最终都不生效。
mounted:实例挂载之后,生成了经过vue编译的真实dom,页面被渲染,对dom的操作均有效,初始化过程结束,一般在此开启定时器、发送网络请求、订阅消息、绑定自定义事件等操作。
beforeUpdate:页面更新之前,此时数据是最新的,页面还是旧的,页面和数据尚未保持同步。
updated:页面更新之后,数据时新的,页面也是新的,数据和页面保持同步,完成了model-view的更新。
beforeDestory:实例销毁之前,data里的数据和methods的方法、指令等都可以使用,但操作数据不会触发更新流程,一般在此关闭定时器、解绑自定义事件、取消订阅等操作。
destory:实例销毁之后,自定义事件会失效,但原生的dom事件依然有效。
使用keep-alive缓存后会有路由组件独有的生命周期钩子
actived:被缓存的组件被激活(显示)时使用
deactivated:被缓存的组件失活(隐藏)时使用
特殊的生命周期钩子
$nextTick():在页面下次更新渲染时执行

6、data为什么是函数

在Vue中,组件的data必须是一个函数,这样每个实例可以维护一份被返回对象的独立的拷贝。如果你使用对象形式定义data,那么所有的组件实例将共享这个对象,从而导致一个组件实例的状态变化会影响到所有使用这个状态的组件实例。

7、路由传参
 1、 this.$router.push进行编程式路由跳转
 
 2、 router-link 进行页面按钮式路由跳转

3、 this.$route.params获取路由传递参数

4、this.$route.query获取路由传递参数

5、 params 和 query 都是传递参数的,params不会在url上面出现,并且params参数是路由的一部分,是一定要存在的 query则是我们通常看到的url后面的跟在?后面的显示参数

Vue 中页面传值的多种方式详解_vue页面传值-CSDN博客

url拼接参数:“/a?a1=a1”,接收页面:this.$route.query.a1

query传参:{path: ‘a’, query: {a2:‘a2’}},接收页面:this.$route.query.a2

params传参:{name: ‘a’, params: {a3:‘a3’}},接收页面:this.$route.params.a3

动态路由传参:/path/a4 ,接收页面:this.$route.params.id,路由:path: “/a/:id”

【vue】vue路由传参的三种方式-CSDN博客

在Vue.js中,路由的使用主要依赖于Vue Router,下面我将给出你所要求的几种场景的简单代码示例。

  1. 使用this.$router.push进行编程式路由跳转

当你想通过代码来触发路由跳转时,可以使用this.$router.push。以下是传递参数的示例:

// 传递params参数
this.$router.push({ name: 'RouteName', params: { userId: 123 }});

// 传递query参数
this.$router.push({ path: '/user', query: { plan: 'private' }});

注意:使用params时,路由必须使用命名路由;而query参数则不受此限制。

  1. 使用router-link进行页面按钮式路由跳转

router-link组件允许你通过声明方式进行路由跳转,并可以传递参数:

<!-- 传递params参数 -->
<router-link :to="{ name: 'user', params: { userId: 123 }}">用户</router-link>

<!-- 传递query参数 -->
<router-link :to="{ path: '/user', query: { plan: 'private' }}">用户</router-link>
  1. 使用this.$route.params获取路由传递参数

当你需要获取通过params传递的参数时,可以在目标组件内使用this.$route.params

created() {
  // 假设路由为/user/123
  const userId = this.$route.params.userId;
}
  1. 使用this.$route.query获取路由传递参数

对于通过query传递的参数,你可以在目标组件内使用this.$route.query来获取:

created() {
  // 假设URL为/user?plan=private
  const plan = this.$route.query.plan;
}
  1. paramsquery的区别
  • params参数通过URL的路径部分传递,不会在浏览器的地址栏中显示。为了使用params,路由必须定义动态片段或使用命名路由。params是必须的,如果没有提供足够的params,路由不会成功跳转。
  • query参数通过URL的查询字符串传递,格式为?key=value,并且会显示在地址栏中。query参数不是路由的一部分,因此它们对路由匹配不是必须的。
8、父子传值

vue组件之间的五种传值方法(父子\兄弟\跨组件)_vue兄弟组件传值的五种方法-CSDN博客

父传子:props、 a t t r s / attrs/ attrs/listeners、 c h i l d r e n 、 children、 childrenroot、provide/inject、$refs

子传父: e m i t 、 emit、 emitparent、

同级传:eventBus、vuex

  • 父传子

image-20240302112058683

image-20240301200625467

子组件中的data:如果content只是从父组件接收的prop,那么在子组件中就不需要再将其定义在data里。data用于组件自己的状态,而props用于从外部接收数据。

  • 子传父:

image-20240302103915292

  • 兄弟传值

vue组件之间的五种传值方法(父子\兄弟\跨组件)_vue兄弟组件传值的五种方法-CSDN博客

组件单独维护自己的状态

当你使用数组形式定义props时,你只是简单地列出父组件可以传递给子组件的属性名称。这种方式比较简洁,适合于那些不需要额外配置的属性。例如:

props: ['content', 'title']

这里,contenttitle都是可以从父组件接收的prop名称。使用数组定义时,Vue不会对传递的数据类型进行检查,也不会有默认值或其他验证。

对象形式的props定义允许你对每个prop进行更详细的配置,包括类型检查、默认值、必需性验证等。例如:

props: {
  content: String,
  title: {
    type: String,
    required: true
  },
  count: {
    type: Number,
    default: 0
  }
}

在这个例子中,content需要是一个字符串,title也需要是一个字符串但它是必需的,而count是一个数字,默认值为0。使用对象形式可以让你的组件接口更清晰,并且提供了基本的类型检查和默认值设置,有助于避免错误和提高代码的健壮性。

子组件通过$emit发送一个事件给父组件,然后父组件的方法useMessage被调用来处理这个事件。这里的关键是父组件完全控制着它自己的状态。子组件并没有直接修改父组件的message属性;相反,它通过事件发送了一个消息,父组件决定如何响应这个事件。这是符合单向数据流原则的:

  • 子组件不直接修改父组件的状态:它通过事件($emit)发出一个信号(以及可能携带的数据),告诉父组件某些事情发生了。
  • 父组件控制自己的状态:父组件监听到事件后,可以决定如何处理这个事件。在这个过程中,父组件可能会更新自己的状态,但这是基于它自己的逻辑和决策,而不是子组件直接造成的。

为什么这不破坏单向数据流?

  • 明确的数据所有权和流向:在这种模式下,父组件仍然拥有和控制自己的状态,子组件仅仅是触发了一个更新的机会。这保持了数据的流向和操作的清晰性。
  • 可预测性和可维护性:通过这种方式,Vue应用的数据流动保持了可预测性。开发者可以轻易地追踪数据是如何、在何时被更新的,因为所有的状态更新都遵循了相同的模式:响应事件。

总的来说,Vue的这种设计允许开发者在保持数据流清晰和可控的同时,实现复杂的组件通信。它避免了直接的父子组件状态操作,而是采用了一种更声明性、更可控的事件通信方式。这样既保证了数据的安全性和一致性,也让组件之间的通信更加灵活和解耦。

9、路由守卫

面试必备:VUE面试题(含答案)_vue面试题必问题和答案-CSDN博客全局守卫:beforeEach(登录拦截)、afterEach

路由独享守卫:beforeEnter(部分路由的登录拦截)

组件内守卫:beforeRouteEnter(权限管理)、beforeRouteUpdate、beforeRouteLeave

路由全局解析守卫:beforeResolve(这里根据单页面name的指向不同,去访问的接口域名也不同)

三个参数:to:去哪,from:从哪来,next:下一步

Vue路由守卫(通俗易懂)-CSDN博客

    {
        path: '/',
        name: 'test',
        component: Test,
        meta:{
            isAuth:true,
            title:'测试页面',
        }

    },

image-20240302190219411

router.beforeEach((to, from, next) => {
    //如果路由需要跳转
    if (to.meta.isAuth) {
        if (localStorage.getItem('name') === 'daetz') {
            next()  //放行
        } else {
            alert('抱歉,您无权限查看!')
        }
    } else {
        // 否则,放行
        next()
    }
});

image-20240302190127193

10、DOM

出现Uncaught ReferenceError: VueRouter is not defined错误通常意味着在尝试使用VueRouter时,JavaScript运行时环境中没有找到VueRouter的定义。这个问题最常见的原因包括:

  1. 未引入Vue Router库:在你的代码中使用VueRouter之前,需要确保已经正确引入了Vue Router库。如果是在HTML文件中工作,需要在使用VueRouter之前,通过<script>标签引入Vue Router的库文件。
  2. 引入顺序错误:如果VueRouter<script>标签位于使用它的脚本之前,可能会导致这个问题。确保先引入Vue.js库,然后再引入Vue Router库。
  3. 模块系统问题:如果你在使用ES模块或CommonJS模块系统(例如,在Vue CLI项目中),确保你已经正确导入了VueRouter。如果忘记导入或导入语句有误,也会遇到这个问题。
11、v-if 与v-for

image-20240229165239294

12、 r o u t e r 和 router和 routerroute的区别

1、 r o u t e r 是用来操作路由, router是用来操作路由, router是用来操作路由,route是用来获取路由信息

2、$router是VueRouter的一个实例,他包含了所有的路由,包括路由的跳转方法,钩子函数等,也包含一些子对象(例如history)

3、 r o u t e 是一个跳转的路由对象(路由信息对象),每一个路由都会有一个 route是一个跳转的路由对象(路由信息对象),每一个路由都会有一个 route是一个跳转的路由对象(路由信息对象),每一个路由都会有一个route对象,是一个局部的对象。

前端面试:Vue中router和route的区别是什么?你可以这么回答_哔哩哔哩_bilibili

image-20240301142805427

那些使用的是router,那些是route

  • router:指的是VueRouter的实例。它主要用于进行路由的操作,比如编程式地导航到不同的路由(使用router.pushrouter.replace等方法),监听路由变化,或是获取整个路由的信息。当你需要控制路由跳转或访问路由的全局信息时,你会用到router
  • route:指的是当前激活的路由的状态信息,可以通过this.$route访问。它是一个路由信息对象,包含了如pathqueryparamshash等当前路由的详细信息。当你需要获取当前路由的参数或查询字符串等信息时,你会用到route

简而言之,router是用于操作和控制路由的工具,而route是当前路由的信息快照。在Vue组件中,你可以通过this.$router访问router实例,通过this.$route访问当前路由的信息对象route

创建Vue根实例

new Vue({
  router,
  render: h => h(App)
})

这里,new Vue({...})创建了一个新的Vue根实例。这是任何Vue应用的起点。在这个实例中,你可以传递一个选项对象来配置这个Vue实例。这个选项对象可以包含数据对象、计算属性、方法和生命周期钩子等。在这个例子中,传递的选项包括routerrender函数。

router配置

router,

这行代码将之前创建的Vue Router实例(router)传递给Vue根实例。这样做的目的是将路由功能整合到Vue应用中。这意味着Vue实例及其所有子组件都可以访问到路由功能,包括this.$routerthis.$route。这是必须的步骤,因为它告诉Vue如何处理应用的路由。

render函数

render: h => h(App)

render函数是Vue中的一个高级特性,用于动态渲染组件。这个函数接收一个创建元素的函数h作为参数,然后返回h(App)。这里的App是一个Vue组件,通常是应用的根组件。简而言之,这行代码的作用是告诉Vue实例要渲染的内容是App组件。

挂载Vue实例

.$mount('#app')

.$mount('#app')方法是Vue实例的挂载方法。它告诉Vue实例应该挂载到DOM中的哪个元素上。在这个例子中,它将Vue实例挂载到id为app的DOM元素上。这意味着App组件(及其所有子组件)的渲染结果将会替代页面上id为app的元素。

为什么需要注册到Vue中?

注册router到Vue实例中是必要的,因为这样做能够在整个Vue应用中启用Vue Router的路由功能。没有这个步骤,Vue实例和其组件将无法访问路由信息(如当前路由路径、查询参数等),也无法使用Vue Router提供的功能和钩子(如导航守卫)。简单来说,这个过程将Vue Router与Vue应用紧密集成,使得开发者可以在应用中方便地使用路由来构建单页面应用(SPA)。

六、参考链接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值