1.新增语义化标签
<section> 定义文档中的区段,页面上的版块,用于划分页面上的不同区域,或者划分文章里不同的节
<nav>定义导航
<asider> 定义文章的侧边栏
<figure> 标签规定独立的流内容(图像、图表、照片、代码等等)。
<figcaption> figure的子元素 用于对figure的内容 进行说明
<header>定义页眉、网页或section的头部
<footer>定义页脚 ,网页或section底部的内容
<hgroup>定义对网页标题的组合
<time></time>定义日期和时间
<dialog>定义一个对话框
<datalist></datalist>选项列表。与 input 元素配合使用,来定义 input 可能的值。
<mark>在视觉上向那些想要突出的文字,比如搜索结果中向用户高亮显示搜索关键词
<details></details>标签用于描述文档或文档某个部分的细节,summary是details元素的标题
< summary></summary> details 元素的标题。该元素用于摘录引用等 应该与页面的主要内容区
分开的其他内容
<progress> 进度条,运行中、加载中的进度。
<meter> 数据区间中绘制一个值的占比与状态
<audio></audio>定义音频,可以支持多个source(媒介标签,这里没有写错,这个标签可
以省略/),浏览器默认将第一个能识别的格式进行播放
<video></video> 定义电影片段或者其他视频流,支持三种类型的视频: Ogg、MPEG4、WebM
<svg>使用XML技术绘制可缩放矢量图形的语言,可使用扩展名.svg的xml定义,也可以内嵌在html中
<canvas> 用来进行canvas绘图,该标签为图形容器,通过js找到标签的操作对象来画图
2.什么是闭包,会对浏览器性能 有什么影响
闭包是指在一个函数内部定义的函数,并且内部函数可以访问外部函数的变量。闭包使得内部函数可以保留对外部函数作用域中变量和参数的引用,即使外部函数已经执行完毕,内部函数仍然可以访问和操作外部函数的变量。这种特性使得闭包在JavaScript中具有很大的灵活性和功能性,可以用于实现模块化、私有变量、函数式编程等。
闭包对浏览器性能有一定的影响,主要体现在以下几个方面:
- 内存消耗:闭包会导致函数的作用域链得不到释放,因此可能会导致内存泄漏,尤其是在循环中使用闭包时需要格外注意,因为每次循环都会创建一个闭包,如果不及时释放,会导致大量内存占用。
- 性能消耗:由于闭包会保留对外部作用域中变量的引用,因此在访问这些变量时需要额外的查找和处理,可能会导致一定的性能损耗。特别是在频繁使用闭包的场景下,可能会对性能产生一定的影响。
虽然闭包可能会对浏览器性能产生一定的影响,但在实际开发中,通常这种影响是可以接受的。合理地使用闭包,避免滥用和循环引用,可以最大程度地减少对性能的影响。同时,现代浏览器在对闭包的处理上也进行了优化,对于一般的使用场景,闭包带来的性能损耗并不会对用户体验产生明显的影响。
3.作用域有哪些
1)什么是作用域
Javascript中的作用域说的是变量的可访问性和可见性。也就是说整个程序中哪些部
分可以访问这个变量,或者说这个变量都在哪些地方可见。
2) 作用域的类型
全局作用域
任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的
变量可以在程序的任意位置访问
局部作用域
函数作用域也叫局部作用域,如果一个变量是在函数内部声明的它就在一个函数作用域
下面。这些变量只能在函数内部访问,不能在函数以外去访问。
块级作用域
ES6引入了`let`和`const`关键字,和`var`关键字不同,在大括号中使用
`let`和`const`声明的变量存在于块级作用域中。在大括号之外不能访问这些变量。
4.ajax 的流程
1) 创建 ajax
const xhr = new XMLHttpRequest()
2) 配置 ajax
xhr.open()
3) 发送 ajax
xhr.send()
4) 监听 ajax
xhr.onload = function () {
console.log(xhr.responseText)
}
Ajax的工作原理相当于在用户和服务器之间加了一个中间层(AJAX引擎),使用户操作与服务器响应异
步化。客户端发送请求,请求交给xhr,xhr把请求提交给服务器,服务器进行业务处理,服务器响应数据
交给xhr对象,xhr对象接收数据,由javascript把数据写到页面上
ajax 流程
利用了一个数字表明 ajax 当前运行到哪一步了
0:ajax 创建完毕
1:ajax 配置完成
2:ajax 发送完毕(后端已经对请求做出响应,并把请求返回 浏览器)
3:浏览器开始解析后端返回的内容,如果返回的数据比较少,那么此时就可以使用数据了,但是
有可能没有解析完毕,数据不完整,所以不推荐在这里使用数据
4: 浏览器的解析的内容已经全部处理完毕,我们可以开始是用数据了
5.继承
1) 原型继承
这种继承方式是将 自己的原型对象更改为 要继承的 父类的 实例化对象
缺点 自己的原型 被修改了
2)借用继承
借用继承就是将属性继承到自己的身上 这种继承方式 可以将父级的所有属性继承到子类
对象自身 但是父类的原型上的属性和方法,跟子类没有任何关系
3)组合继承
基于上述,将原型继承和借用继承组合起来,创建了一个 组合继承
优点: 能够继承到所有的属性和原型上的方法 并且属性能够继承到对象本身
缺点: 在原型上会多一套多余的属性
4)拷贝继承
5)ES6继承
在 实现 ES6 类的继承的时候,书写方式有几个要求
1. class 子类的类名 extends 要继承的父类类名 {}
2. constructor 内部 内部必须书写 super
它的 作用可以在调用的时候 对他进行传参,传参的参数会传递到 父类 中
注意: 哪怕父类不需要任何参数,我们的 super 也需要书写
并且需要书写在 constructor 内部的 第一行
当前方法只能 给 class 类 使用
但是可以继承到构造函数中的 内容, 也就是说 父类是 构造函数或者 class 都可以
6.原型链和 作用域链 的区别
原型链和作用域链是两个不同的概念,它们在 JavaScript 中起着不同的作用。
原型链是指对象之间的关联关系。在 JavaScript 中,每个对象都有一个指向其原型对象的内部链接。当访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript 引擎会沿着原型链向上查找,直到找到对应的属性或方法或者到达原型链的顶端为止。
作用域链是指在 JavaScript 中变量和函数的作用域关系。作用域链是由函数创建时的作用域环境决定的,它决定了函数内部可以访问到哪些变量和函数。当在函数内部访问一个变量或函数时,JavaScript 引擎会沿着作用域链向上查找,直到找到对应的变量或函数或者到达全局作用域为止。
因此,原型链和作用域链是两个不同的概念,原型链是用于查找对象的属性和方法,而作用域链是用于确定变量和函数的作用域范围。
7.模块化
必备条件
1)必须是服务器启动页面
2)在 script 标签 内 添加 type="module"
导出 export default { } 一个 文件只能书写一个
导入 import 变量 from '文件地址'
导出 export 变量
导入 import { 一一对应 } from '文件地址'
8.开发中用到对象 与 数组
数组: 开发中 比如说 商品列表。一些大体相同的
对象:针某一东西的详情
9.
const obj = { a:[] } 修改 属性 a 的地址 可不可以更换?
const onj = { a: [], name: 'sdaq' } 可不可以修改?
10. ES6 新增的方法 和 东西
1)解构赋值
2)箭头函数
3)展开运算符
4)this 指向
5)对象的优化
6)Set 与 Map 数据结构
11. promise
Promise 是 JavaScript 中用于处理异步操作的一种机制。它是一种用于处理异步操作的对象,可以让我们编写更加优雅和可读的异步代码,避免了回调地狱的问题。
Promise 对象代表一个异步操作的最终完成或失败,以及其结果值。一个 Promise 对象有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。当一个异步操作完成时,Promise 对象的状态会从 pending 变为 fulfilled,当异步操作失败时,状态会从 pending 变为 rejected。
Promise 对象有两个重要的方法:then 和 catch。then 方法用于指定当异步操作成功时的回调函数,catch 方法用于指定当异步操作失败时的回调函数。通过这两个方法,我们可以对异步操作的结果进行处理,避免了传统的回调函数嵌套,使得代码更加清晰和易于维护。
另外,Promise 还具有链式调用的特性,可以通过 then 方法返回新的 Promise 对象,从而实现多个异步操作的串联,提高了代码的可读性和可维护性。
总之,Promise 是一种用于处理异步操作的机制,它可以让我们更加优雅地处理异步代码,避免回调地狱,提高代码的可读性和可维护性。
12. 构造函数 的注意事项
1)构造函数的函数名 建议首字母大写 (为了和普通函数 做一个区分)
2)构造函数将来在调用的时候,必须和 new 关键字 一起使用
3)构造函数内部 不需要书写 return
如果 手动返回了 基本数据类型,那么写了和 没写一样
如果 手动返回了 引用数据类型,那么写了之后构造函数失效
4)构造函数在使用的时候 内部 的 this 规则和 之前的 函数不太一样
因为一个函数和 new 关键字
13. 两个数组 和并 并删除第二个数据
<script>
let arr1 = [1,2,3,4,5]
let arr2 = [3,4,5,6,7]
let arrA = [...new Set([...arr1,...arr2])]
arrA.splice(1,1)
console.log(arrA)
</script>
14. 同步异步,宏任务与微任务
js是单线程的,所有的任务都要排队挨个执行,就好比做保健(执行js代码),
保健师傅只有一个(单线程),顾客(js代码)需排队享受服务,
排队的顺序按照顾客的种类(同步异步、宏任务微任务)和顾客到店顺序(在代码中的位置)执行
同步与异步、宏任务和微任务分别是函数两个不同维度的描述。
异步任务:setTimeout和setInterval、ajax、事件绑定等
同步任务:除了异步任务外的所有任务
微任务:process.nextTick和 Promise后的theny语句和catch语句等
宏任务:除了微任务以外的所有任务
15. 解决跨域
1) 为什么会 出现 跨域
同源策略 是 浏览器最基本的安全功能,如果缺少了 同源策略,浏览器很容易受到 XSS、CSFR
等攻击
同源策略 指的是 协议 + 域名 + 端口 三者相同 只要有一个 不同 就会出现 跨域
2) 跨域 会导致 什么 发生
请求能够正常发送
服务器也一定能够正常响应
但是浏览器 会认为 当前的请求不安全,然后将本次请求 的 信息拦截掉
3) 解决跨域 的几种方式
1. jsonp
2. cors
3. proxy 服务器代理
4)jsonp 解决
<script src='/static/js/index.js'></script>
script 的 src 属性 会将地址中的文件内容读取一遍,
然后将 文件的内容当成 JS 代码执行一遍
<script src="http://localhost:8081/api"></script>
目前我们的这个写法其实就是利用了 jsonp 解决了 跨域
因为同源策略是浏览器用来限制 ajax 的
script 标签的 src 属性,不会受到限制,所以可以跳出同源策略
但是当前的解决方案也不是特别完美,因为目前的 jsonp 只能处理
get 方式的跨域,post 方式无法解决
5)cors 解决
使用之前先执行命令 npm i cors 确保已经安装上
出现跨域的流程
1.前端发送请求(发送成功)
2.后端反馈响应(反馈成功)
3.浏览器解析后端数据(此时发现当时的请求违反了 同源策略,所以触发了跨域,
将后端反馈的数据浏览器拦截掉)
4.现在前端没有办法正常的接收到后端的数据
cors 解决跨域的思路
1.前端发送请求(发送成功)
2.后端反馈响应(反馈成功) 但是在反馈的时候告诉浏览器我们这次通讯是合法
的不要拦截
3.浏览器解析后端反馈的数据(此时发现了当前的请求违反了 同源策略,但是后端
告诉我们
当前的请求时合法的,所以不触发跨域,正常给前端反馈数据)
4.前端此时正常接收到数据了
再接口处理的响应报文函数中
res.setHeader(
"Access-Control-Allow-Headers",
"Content-Type, X-Custom-Header"
); // 允许所有跨域网站的响应值
res.setHeader("Access-Control-Allow-Methods", "POST, GET"); // 允许这四个方法
res.setHeader("Access-Control-Allow-Methods", "*"); // 允许所有方法
6) proxy 服务器 代理
字面意思可以理解为中间商,开启代理,原理就是在本地创建一个虚拟服务器,发送请求数据,
同时接受请求的数据,利用服务器与服务器间,交互,不会有跨域问题,也是完全只靠前端
自己独立解决跨域的方式
16. BFC 的相关事宜
1) 触发 BFC
根元素 html
float 不为 none
display: inner-block,table-cell, table-caption, flex, inner-flex
position: absolute/fixed
overflow 不为 visible
2) BFC 布局规则
1.内部的Box 会在垂直方向, 一个接一个的放置
2.Box 垂直方向的距离由 margin 决定。 属于同一个 BFC 的两个相邻的 box 的 margin 会
重叠,按照最大的 margin 值计算
3.每个元素的 margin box 的左边, 与包含块 border box 的 左边相接触
4.BFC 的 区域 不会与 float box 重叠
5. BFC 会形成一个 独立的 容器, 容器里面的 子元素 不会 影响到外面的 元素
6. 计算 BFC 的 高度是,浮动元素也参与 计算
3) BFC 应用
1.自适应两栏 布局
2. 清除内部 浮动
3.防止 margin 重叠
17. 本地存储 的区别
1.storage 与 cookie 的区别
1)出现时间:
cookie: jS 出现 就有了
storage: 在 H5 的时候才有
2)存储大小:
cookie: 4 kb 左右
storage: 5mb~20mb
3)前后端 交互:
cookie: 前后端交互会自动携带
storage: 交互时不会手动携带,但可以手动携带
4)前后端操作
cookie: 前后端都可以 操作
storage: 只能前端操作
5)过期时间:
cookie:可以手动设置时间
storage: 没有 过期时间
2. localStorage 与 sessionStorage
1)跨页面通讯
localStorage: 可以跨页面通讯
sessionStorage:必须是当前页面 才可以实现 跨页面通讯
2)存储时间:
localStorage: 持久化存储
sessionStorage: 临时存储,当前页面关闭就没有了
共同点
存储的必须为 字符串
18. 数据类型转换
19。 == 与 === 的区别
== 不判断数据类型
=== 判断数据类型
20。 同源策略 (跨域)
同源策略:是一个重要的安全策略,它用于限制一个 源 的文档或者 它加载的脚本如何能与另一个源
的资源进行交互
是一种 约定, 由 Netscape 公司 1995 年引入浏览器,它是 浏览器最核心也最基本的
安全功能,所有使用 JavaScript 的 浏览器都 会使用 这个策略。如果缺少了 同源
策略,浏览器很容易受到 XSS、CSFR 的攻击
21. get 与 post 的 区别
GET: 获取 的含义
POST: 提交的含义
传参的差异:
GET: 直接在后边 拼接,格式 类似于 查询字符串
POST: 在 请求体: {xhr.send( 在这里 书写 )}
传参的大小
GET: 2kb 左右
POST: 原则上没有限制,但可以在后端 添加
传参的安全性
GET: 明文传输,相对不安全
POST: 密文传输,相对安全
传参的格式:
GET: 传递的是查询字符串
POST: 原则上也没有限制,但是传参 的时候需要通过
content-type 指定我们传参的格式
22. /^[a-z0-9]{6,8}$/i
23. jS 数据类型有哪些?
基本数据类型:
number,string,null,undefined,boolean
引用数据类型
array,object,function
24. 判断数据类型的 所有方法
1. typeof
2. 数据.__proto__.constructor 类型
3. Objct.prototype.toString.call(数据)
4. instanceof
25. const a1 = { id: 'Qf001' }
const a2 = a1
a2.name = '张三'
? a1 中是否有?
深浅拷贝
26. ajax post 发生请求
post 的 参数一定 书写在 xhr.send() 的 小括号中
并且 我们也可以 传递 查询字符串
需要设置请求头
xhr.setRequestHeader('content-type','application/json') 或者
xhr.setRequestHeader('content-type', 'applocation/x-www-form-urlencoded')
xhr.send(JSON.stringify({
name: '张三',
age: 15
}))
27. 修改 this 指向
call()
apply()
bind()
28. 事件委托
1) 什么是事件委托
在 javaScript 中, 事件委托 也称为 事件托管或 事件代理,就是把目标节点的事件绑定到
祖先节点上。这种方式是基于事件传播过程中逐层冒泡总被祖先节点捕获
2)为什么 用 事件委托
1.节省监听数,节省内存
2.可以动态监听元素
事件冒泡:
当一个元素接收到事件的时候,会把他接收到的事件传递给自己的父级,一直到 window
事件源 => 根节点(由内到外) 进行事件传播
事件捕获
当鼠标点击或者触发 dom 事件时(被触发 dom 事件的 这个元素被叫作 事件源),浏览器会从
根节点 => 事件源 (由外到内) 进行事件传播
29. 拖拽实现思路
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
div{
width: 100px;
height: 100px;
background-color: aqua;
position: absolute;
top: 0;
left: 0;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
const box = document.querySelector('.box')
let pageX = 0
let pageY = 0
let pageMoveX = 0
let pageMoveY = 0
let flag = false
box.onmousedown = function (e) {
flag = true
pageX = e.clientX
pageY = e.clientY
pageMoveX = box.offsetLeft
pageMoveY = box.offsetTop
}
document.onmousemove = function (e) {
if(!flag) return
let moveX = e.clientX - pageX
let moveY = e.clientY - pageY
let left = moveX + pageMoveX
let top = moveY + pageMoveY
if(left <= 0) left = 0
if(top <= 0) top = 0
console.log(innerHeight,innerWidth)
if(left > innerWidth - box.offsetWidth) left =
innerWidth - box.offsetWidth
if(top > innerHeight - box.offsetHeight) top =
innerHeight - box.offsetHeight
box.style.left = left + 'px'
box.style.top = top + 'px'
}
box.onmouseup = function () {
flag = false
}
</script>
</body>
</html>
30. 作用域, 变量提升, 作用域链, 暂时性死区
作用域
变量的访问
31. JS 影响性能
1.闭包
内存空间不被销毁,内存泄漏
2.大批量的操作 DOM 节点
JavaScript(JS)可以对性能产生影响,特别是在网页应用程序中。以下是一些主要的方面:
1. 页面加载时间:大量或低效的JavaScript代码可能导致页面加载时间延长。浏览器需要下载、解析和
执行JavaScript代码,因此过多的或复杂的代码会增加页面加载时间。
2. 内存消耗:JavaScript代码的执行可能占用大量内存,尤其是在处理大型数据结构或循环时。不合理
的内存消耗可能导致页面卡顿或崩溃。
3. CPU消耗:复杂的JavaScript代码可能导致浏览器消耗更多的CPU资源,尤其是在执行大量计算或循环
时。这可能影响其他页面元素的响应速度。
4. 事件处理:大量的事件处理器或监听器可能导致页面响应变慢,尤其是在处理大量用户交互时。
5. 网络请求:JavaScript通常用于发起网络请求,例如获取数据或资源。如果请求过多或请求不合理,
可能导致网络负载过重,影响页面性能。
为了优化JavaScript代码的性能,可以考虑以下方法:
- 精简和压缩JavaScript代码,以减少文件大小和加载时间。
- 避免使用过多的全局变量,以减少内存消耗。
- 使用事件委托和事件监听器池来管理事件处理。
- 合理使用缓存和异步加载,以减少网络请求。
- 使用性能监测工具和浏览器开发者工具来分析和优化JavaScript代码。
综上所述,JavaScript在网页应用程序中的使用可能会对性能产生影响,但通过合理的优化和管理,可以
最大程度地减少这些影响。
32. 创建对象的 方式
JavaScript 中有多种方式可以创建对象。以下是其中一些常见的方式:
-
对象字面量:
使用对象字面量直接创建对象,这是一种简单而常见的方式。let person = { name: "John", age: 30, sayHello: function() { console.log("Hello!"); } };
-
构造函数:
使用构造函数和new
关键字创建对象,构造函数可以用来初始化对象的属性。function Person(name, age) { this.name = name; this.age = age; this.sayHello = function() { console.log("Hello!"); }; } let person = new Person("John", 30);
-
Object.create:
使用Object.create
方法创建对象,该方法可以指定原型对象。let personPrototype = { sayHello: function() { console.log("Hello!"); } }; let person = Object.create(personPrototype); person.name = "John"; person.age = 30;
-
工厂函数:
使用工厂函数创建对象,工厂函数是一个返回对象的函数。function createPerson(name, age) { return { name: name, age: age, sayHello: function() { console.log("Hello!"); } }; } let person = createPerson("John", 30);
-
ES6 类:
使用ES6中的类语法创建对象,类是一种更加面向对象的方式来创建对象和定义方法。class Person { constructor(name, age) { this.name = name; this.age = age; } sayHello() { console.log("Hello!"); } } let person = new Person("John", 30);
这些都是在JavaScript中创建对象的常见方式,每种方式都有其适用的场景和特点。
33.本地存储的方案 有什么区别
34.实现 本地存储
35.
let t = 1
function a(text) {
let t = text++
}
a(t)
console.log(t)
36. 原生JS 做过什么事情
37. JSON 数据类型的理解
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它基于JavaScript对象字面量的语法。JSON数据类型的理解可以从以下几个方面展开:
- 语法:JSON采用了类似于JavaScript对象字面量的语法,包括键值对、数组、字符串、数字、布尔值和null。它使用了简洁的文本形式来表示数据,易于阅读和编写。
- 数据类型:JSON支持的数据类型包括字符串、数字、布尔值、数组、对象、null和嵌套组合。它可以表示复杂的数据结构,例如嵌套的对象和数组。
- 应用:JSON通常用于数据的序列化和反序列化,例如在Web应用中进行客户端和服务器之间的数据交换。它也被广泛应用于API的数据传输和存储。
- 跨语言性:JSON是一种语言无关的数据格式,因此可以在不同编程语言之间进行数据交换。几乎所有的编程语言都有JSON的解析和生成库,因此可以方便地进行数据转换。
- 限制:JSON有一些语法限制,例如键名必须是字符串,不允许注释,不允许使用undefined等。此外,JSON不支持循环引用的对象,因为循环引用会导致无限递归。
总的来说,JSON是一种简洁、易读、跨语言的数据格式,适用于各种应用场景,特别是在Web开发中起着重要的作用。对JSON数据类型的理解可以帮助开发人员更好地处理和交换数据。
38. jsonp 利用什么 原理
JSONP(JSON with Padding)是一种跨域数据请求的解决方案,它利用了HTML中<script>
标签的特性来实现跨域数据传输。JSONP的原理可以简单概括如下:
- 动态创建
<script>
标签:在客户端页面中,通过动态创建<script>
标签的方式向服务器端发起跨域请求。例如,假设我们要从http://example.com/data
获取数据,可以创建一个类似于<script src="http://example.com/data?callback=processData">
的<script>
标签。 - 服务器返回数据:服务器端接收到请求后,将数据包装在指定的回调函数中返回给客户端。在上述例子中,服务器端会返回类似于
processData({...})
的JavaScript代码,其中...
表示实际的数据内容。 - 客户端处理数据:客户端页面中预先定义了名为
processData
的回调函数,因此当服务器返回的JavaScript代码被执行时,实际上是调用了这个预定义的回调函数,并将数据作为参数传入。这样就实现了跨域数据的传输和处理。
JSONP的原理基于浏览器对<script>
标签的跨域请求不受同源策略限制的特性。通过利用这一特性,JSONP可以实现跨域数据请求,但它也有一些局限性,例如只支持GET请求、安全性较差等。随着现代Web开发的发展,CORS(跨域资源共享)等新的跨域解决方案逐渐取代了JSONP,但JSONP作为一种经典的跨域数据请求方式,仍然具有一定的历史意义。
39. 字符串 翻转
40. 判断 数据 类型 方法
41. 如何实现全选的思路 源生写
42. 原型 与 原型链
43. 开发中 使用 this
44. 开发 请求头
45. 什么是同源策略
同源策略(Same-Origin Policy)是一种浏览器安全策略,用于防止一个网页的脚本访问另一个源的
资源。同源策略规定了浏览器只允许页面内的脚本与其所属的源(协议、域名、端口号完全一致)进行
交互,而不允许与其他源进行直接交互。
具体来说,如果一个页面加载自`http://www.example.com`,那么它的脚本只能与
`http://www.example.com`加载的资源进行交互,而不能直接与其他域名的资源进行交互。
同源策略的目的是保护用户的隐私和安全,防止恶意网站窃取用户的信息或进行恶意操作。然而,同源
策略也会对开发者造成一些限制,特别是在跨域资源访问的情况下,需要使用一些特殊的技术手段来绕
过同源策略的限制。
46. 你是如何理解 插件/库/框架 三者的区别
插件、库和框架是在软件开发中常见的概念,它们有着不同的作用和特点。
1. 插件(Plugin):
- 插件通常是一段可被添加到现有软件以增加其功能的代码。它们扩展了软件的功能,允许用户在不
修改原始软件的情况下添加额外的功能或特性。
- 插件通常与特定的软件或平台相关,提供了一种定制化软件的方式,使得用户可以根据自己的需求
来扩展软件的功能。
2. 库(Library):
- 库是一组可重用的代码和资源的集合,用于帮助开发者完成特定的任务。它们通常包含了一系列函
数、类和工具,可以被其他软件项目引用和使用。
- 库的目的是为了提供一些通用的功能,开发者可以在自己的项目中引用这些库来完成特定的任务,
从而避免重复编写相同的代码。
3. 框架(Framework):
- 框架是一个更加完整和综合的工具集,它提供了一整套解决特定问题的解决方案。框架通常包含了
库、工具和规范,以及一些基础设施,用于帮助开发者构建应用程序。
- 相比于库,框架更加具有约束性,它通常会规定开发者按照框架提供的规范和结构来编写应用程
序,从而使得应用程序更加统一和易于维护。
总的来说,插件、库和框架都是在软件开发中用于提高开发效率和功能扩展的工具,它们在功能、复杂度和
使用方式上有所不同,开发者可以根据具体的需求选择合适的工具来完成任务。
47. 什么是 nodejs, 它可以用来做些什么事情?
Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,用于构建快速、可扩展的网络应用程
序。它使得开发者能够使用JavaScript语言在服务器端运行代码,而不仅仅局限于在浏览器端执行。
Node.js可以用来做以下事情:
1. 服务器端编程:Node.js的主要用途是构建服务器端应用程序。它可以处理HTTP请求、响应、路由、文
件操作等,因此非常适合构建Web服务器、API服务器等。
2. 实时应用程序:Node.js对于实时应用程序(如聊天应用、协作工具、在线游戏等)特别有用,因为它
支持事件驱动的非阻塞I/O模型,能够处理大量并发连接。
3. 命令行工具:Node.js可以用来构建命令行工具,可以帮助开发者进行自动化、脚本编写等任务。
4. 数据库操作:Node.js可以用于访问数据库,进行数据的读取、写入、更新等操作,因此在构建数据库
相关的应用时也非常有用。
5. 微服务架构:Node.js可以作为微服务架构中的一部分,用于构建小型、独立的服务,以便于实现系统
的解耦和横向扩展。
总的来说,Node.js是一个灵活、高效的运行时环境,可以用于构建各种类型的应用程序,尤其是那些需要
处理大量I/O操作、实时性要求高的应用。由于其基于JavaScript语言,也使得前端开发者可以更容易地转
向后端开发,实现全栈开发。
48. dom 节点操作
DOM节点可以进行多种操作,包括但不限于以下几种:
- 访问和修改节点属性:可以通过节点对象的属性来获取和修改节点的各种属性,如id、className、style等。
- 修改节点内容:可以通过节点对象的 innerHTML、innerText、textContent 等属性来修改节点的文本内容。
- 创建新节点:可以使用 document.createElement() 方法创建新的元素节点,document.createTextNode() 方法创建文本节点,以及 document.createDocumentFragment() 方法创建文档片段。
- 添加、删除和替换节点:可以使用 appendChild()、removeChild()、replaceChild() 等方法来添加、删除和替换节点。
- 遍历和查找节点:可以使用 querySelector()、querySelectorAll()、getElementsByTagName()、getElementsByClassName() 等方法来查找和获取节点。
- 添加和移除事件监听器:可以使用 addEventListener()、removeEventListener() 方法来添加和移除事件监听器。
- 修改节点样式:可以通过节点对象的 style 属性来修改节点的样式。
- 操作节点的 class:可以通过节点对象的 classList 属性来添加、删除和切换节点的类名。
- 操作节点的尺寸和位置:可以通过节点对象的 offsetWidth、offsetHeight、offsetLeft、offsetTop 等属性来获取节点的尺寸和位置信息,也可以通过设置 style 属性来修改节点的尺寸和位置。
这些操作使得开发者可以在网页中动态地操作和管理节点,实现丰富的交互效果和动态内容。DOM的操作是前端开发中非常基础和重要的部分,熟练掌握这些操作能够帮助开发者更好地构建交互性强、用户体验良好的网页应用。
49. vue 框架 数据 和 方法 往哪里放
数据 data() { return { } }
方法 methods: { }
50. 生命周期
每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行被称为生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码。
51. 计算属性 与 侦听器 的区别
侦听器
1.页面一上来不立即执行,除非添加配置项
2.不具有缓存性
3.可以书写异步代码
4.不需要书写 return
5.一个值的变化可能导致多个 值的变化
计算属性
1.页面一上来立即执行
2.具有缓存性
3.不能书写 异步代码
4.必须书写 return
5. 多对一
52. vue 的 内置指令
v-if
v-show
v-for
v-model
v-slot
53. asynk 与 await 的 用法
avaScript中的async
和await
:
-
async
函数:-
在JavaScript中,
async
函数用于定义一个返回Promise
对象的异步函数。这意味着函数内部可以包含异步操作,并且函数本身将返回一个Promise
。 -
例如:
async function fetchData() { // 异步操作 return data; }
-
-
await
关键字:-
await
关键字用于等待一个Promise
对象的解决或拒绝,并且只能在async
函数内部使用。 -
当使用
await
关键字时,代码将等待Promise
对象的状态改变,然后继续执行后续代码。 -
例如:
async function fetchData() { let data = await fetch('https://api.example.com/data'); // 使用获取到的数据 }
-
54. vue 的组件通信
Vue 的组件通信是指不同组件之间进行数据传递、状态管理和事件触发的机制。Vue 提供了多种方式来实现组件通信,包括 props、事件emit、on、$refs、vuex 等。
- Props 和 Events:父子组件之间通过 props 和 events 进行通信。父组件可以通过 props 向子组件传递数据,子组件可以通过 events 向父组件发送消息。
- emit和on:在非父子关系的组件之间进行通信时,可以使用emit和on 来触发和监听自定义事件。一个组件可以通过 emit触发一个自定义事件,而其他组件可以通过emit触发一个自定义事件,而其他组件可以通过on 监听这个事件来做出相应的处理。
- refs:通过ref属性可以在父组件中直接访问子组件的实例。这样可以通过refs:通过ref属性可以在父组件中直接访问子组件的实例。这样可以通过refs 来直接调用子组件的方法或者访问子组件的数据。
- Vuex:Vuex 是 Vue 官方推荐的状态管理库,用于管理应用的状态。通过 Vuex,不同组件之间可以共享同一个状态,从而实现组件间的通信。
- parent和children:可以通过 parent和children 访问父组件和子组件的实例,从而进行直接的通信。
总的来说,Vue 的组件通信可以通过 props 和 events 实现父子组件之间的通信,而通过 emit和on、refs、parent 和 $children、Vuex 等方法可以实现更灵活的组件间通信。根据具体的场景和需求,选择合适的通信方式来实现组件之间的数据传递和状态管理。
55. git 的常用指令
git add .
git commit -m ''
git push
git log
git reset commitID
56. vue 开发 与 原生开发 的区别
数据驱动视图
57. vue 的响应式原理
vue的响应式原理 主要利用了 Object.defineProperty 的 getter和setter 方法的观察者模式实现的,在组件初始化是 会给data 属性 注册getter 和 setter ,然后 在 new 一个 warcher 对象, 此时 warcher 会 调用 render 函数 去生成 虚拟的 dom, 调用render的时候会用到 data的属性值,data属性发生变化时,就会触发 data 的getter 方法,将当前的 warcher 注册进 sub ,当属性值发生变化时,就会遍历 sub 里所有的 warcher ,重新渲染页面
58. 如何理解虚拟 dom
虚拟 DOM(Virtual DOM)是一种用于优化页面渲染性能的技术。它的核心思想是通过在内存中维护一份虚拟的DOM树来代替真实的DOM树,通过比较虚拟DOM树的变化并最小化对真实DOM的操作,从而提高页面渲染的效率。
虚拟 DOM 的工作原理可以分为以下几个步骤:
- 初始渲染:当页面加载时,虚拟 DOM 会通过JS对象表示整个页面的结构,这个虚拟 DOM 树是一种轻量级的数据结构,它可以很快地进行创建和修改。
- 更新触发:当页面状态发生改变时,比如用户交互、数据更新等,会触发重新渲染。在这个过程中,应用会生成新的虚拟 DOM 树。
- 虚拟 DOM 比较:新生成的虚拟 DOM 树会和之前的虚拟 DOM 树进行比较,找出两者之间的差异。
- 最小化操作:通过比较,找出需要更新的部分,然后将这些差异应用到真实的DOM树上,从而最小化对真实DOM的操作。
这种方式可以减少对真实 DOM 的频繁操作,提高页面渲染性能。因为直接操作真实 DOM 是非常昂贵的,而虚拟 DOM 可以通过批量更新的方式来减少对真实 DOM 的操作次数。
虚拟 DOM 技术的流行得益于其能够提高前端开发效率和页面性能的双重优势。许多流行的前端框架和库,如React和Vue,都采用了虚拟 DOM 技术来进行页面渲染和更新。
59. 你是如何 理解 vue 里 key 属性的
在Vue中,key
属性通常用于在Vue的列表渲染中,用于唯一标识列表中的每个子元素。当列表中的元素发生变化时,Vue会根据key
属性来决定是否重新渲染元素,以及如何更新元素。
具体来说,key
属性的作用包括:
- 提高性能:通过
key
属性,Vue能够更准确地追踪每个列表项的变化,从而减少不必要的DOM操作,提高渲染性能。 - 保持状态:当列表中的元素重新排序或发生变化时,使用
key
属性可以帮助Vue保持每个元素的状态,避免重新创建或销毁元素。
总之,key
属性在Vue中扮演着重要的角色,能够帮助Vue更高效地处理列表渲染中的变化和更新。
60. v-model 的实现原理
v-model
是 Vue.js 中用于实现双向数据绑定的指令。它的原理是将表单元素和数据模型进行双向绑定,当表单元素的值发生变化时,数据模型也会相应地更新,反之亦然。
当你在一个表单元素上使用 v-model
指令时,Vue.js 会自动生成一个事件监听器,用于监听该表单元素的输入事件。当用户在表单元素中输入内容时,该事件监听器会捕获用户输入的值,并将其实时地同步到数据模型中。
举个例子,如果你在一个 <input>
元素上使用了 v-model="message"
,那么当用户在输入框中输入内容时,message
数据模型的值会实时更新;反之,如果你在数据模型中修改了 message
的值,输入框中的内容也会随之更新,实现了双向绑定。
总的来说,v-model
的原理就是通过事件监听和数据绑定实现了表单元素和数据模型之间的双向同步。
61.vue router 的理解
ue Router 是 Vue.js 官方的路由管理器,用于构建单页面应用程序(SPA)。它允许你在应用中通过管理应用的 URL 来实现页面之间的导航和跳转。Vue Router 提供了诸如路由匹配、路由参数、嵌套路由、导航守卫等功能,让你可以轻松地构建复杂的前端路由系统。
通过 Vue Router,你可以定义各种路由规则,配置路由参数,以及在页面跳转前后执行特定的操作。它与 Vue.js 框架无缝集成,能够帮助你构建出结构清晰、交互流畅的单页面应用程序。Vue Router 的灵活性和功能丰富性使得它成为了 Vue.js 开发中不可或缺的一部分。
62. 组合式 API创建响应式 数据
ref,reactive, shallowRef, shallowReactive,toRef,toRefs, toRaw
63. vuex 的五个 核心模块
State(状态)
State即应用程序中需要管理的状态,可以理解为存储数据的地方。在Vuex中,所有的状态都被存储在单一的数据源中,即store。这样做的好处是可以方便地跟踪状态的变化,以及在需要时进行调试和监控。
Getters(获取器) Getters可以理解为store的计算属性,它们的作用是从state中派生出一些状态,类似于Vue组件中的计算属性。通过getters,我们可以对state进行一些复杂的计算或筛选,然后在组件中使用这些派生出的状态。
Mutations(变化)
Mutations是唯一允许修改state的地方。每个mutation都有一个字符串类型的事件类型(type)和一个回调函数,回调函数接受state作为第一个参数。在mutation中,我们可以对state进行同步的修改操作。
Actions(动作)
Actions类似于mutations,不同之处在于actions可以包含异步操作。通过actions,我们可以提交mutation来间接地对state进行修改。这样做的好处是可以将一些异步操作放在actions中,使得我们的代码更加清晰和易于维护。
Modules(模块)
当应用变得非常复杂时,单一的store可能会变得难以维护。Vuex允许我们将store分割成模块(module),每个模块拥有自己的state、getters、mutations和actions。这样做的好处是可以更好地组织代码,使得应用的状态管理更加清晰和可维护。
64. git 常用命令
git add . git commit -m '' git push git log git reset commitID git pull
65. data 为什么是一个函数
在 Vue 组件中,data 选项必须是一个函数,而不能直接是一个对象。 这是因为 Vue 组件可以同时存在多个实例,如果直接使用对象形式的 data 选项,那么所有的实例将会共享同一个 data 对象,这样就会造成数据互相干扰的问题。 因此,将 data 选项设置为函数可以让每个实例都拥有自己独立的 data 对象
66. 组件化开发
JavaScript组件化开发是一种通过将应用程序拆分为独立、可重用的组件来构建应用程序的方法。以下是JavaScript组件化开发的一些优势:
- 可维护性:组件化开发使得应用程序结构更清晰,代码更易于维护。每个组件都是独立的,可以单独开发、测试和维护,从而降低了代码的复杂性。
- 可重用性:组件化开发可以促进代码的重用。可以将通用的组件抽象出来,然后在不同的地方多次使用,从而减少重复编写代码的工作量。
- 可扩展性:通过组件化开发,可以更容易地扩展应用程序。可以根据需要添加、修改或删除组件,而不会对整个应用程序产生太大的影响。
- 并行开发:不同团队成员可以并行开发不同的组件,而不会相互干扰,从而提高开发效率。
- 更好的代码组织:组件化开发促进了更好的代码组织,使得代码更易于理解和维护。每个组件都有自己的职责范围,使得代码更加模块化。
- 更好的测试性:组件化开发使得单元测试更容易,因为每个组件都可以单独进行测试,从而提高了应用程序的质量。
总的来说,JavaScript组件化开发可以提高代码的可维护性、可重用性、可扩展性,促进并行开发,改善代码组织和测试性。这些优势使得组件化开发成为构建现代Web应用程序的重要方法之一。
67.数据驱动视图
数据驱动视图是一种编程范式,通常用于描述前端框架(比如Vue.js和React)中的工作方式。它的核心思想是,视图(用户界面)的状态和展示是由数据的变化来驱动的,而不是由手动操作DOM元素来实现的。以下是对数据驱动视图的理解:
- 数据作为核心:在数据驱动视图的模式下,视图的状态和展示取决于数据的状态。当数据发生变化时,视图会自动更新以反映最新的数据状态。
- 声明式编程:采用数据驱动视图的框架通常支持声明式编程,即通过描述数据应该如何展示来构建用户界面,而不是手动操作DOM元素。这样可以减少对DOM的直接操作,提高开发效率和可维护性。
- 单向数据流:在数据驱动视图的框架中,通常采用单向数据流的模式,即数据从父组件流向子组件,子组件通过props接收数据,而不会直接修改父组件的数据。这种单向数据流的模式有利于数据的追踪和调试。
- 响应式更新:数据驱动视图的框架通常会实现响应式更新,即当数据发生变化时,相关的视图会自动进行更新,而无需手动干预。这种机制可以减少手动DOM操作,提高开发效率。
总的来说,数据驱动视图是一种通过数据状态来驱动用户界面展示的编程模式,它通过声明式编程、单向数据流和响应式更新等特性,提高了开发效率、可维护性和用户界面的一致性。Vue.js和React等流行的前端框架都采用了数据驱动视图的理念。
68.ref 和 reactive 的简单理解
- ref 和 reactive 都是 vue3 的监听数据的方法,本质是 proxy
- ref 基本类型复杂类型都可以监听(我们一般用 ref 监听基本类型),reactive 只能监听对象(arr,json)
- ref 底层还是 reactive,ref 是对 reactive 的二次包装, ref 定义的数据访问的时候要多一个.value
69.谈谈你对 Vue3.0 有什么了解?
-
新增亮点
- 性能比 vue2.x 快 1.2~2 倍
- 支持 tree-shaking,按需编译,体积比 vue2.x 更小
- 支持组合 API
- 更好的支持 TS
- 更先进的组件
-
性能比 vue2.x 快 1.2~2 倍如何实现的呢
-
diff 算法更快
- vue2.0 是需要全局去比较每个节点的,若发现有节点发生变化后,就去更新该节点
- vue3.0 是在创建虚拟 dom 中,会根据 DOM 的的内容会不会发生内容变化,添加静态标记, 谁有 flag!比较谁。
-
静态提升
- vue2 中无论元素是否参与更新,每次都会重新创建,然后再渲染 vue3 中对于不参与更新的元素,会做静态提升,只被创建一次,在渲染时直接复用即可
-
事件侦听缓存
- 默认情况下,onclick 为动态绑定,所以每次都会追踪它的变化,但是因为是同一函数,没有必要追踪变化,直接缓存复用即可
- 在之前会添加静态标记 8 会把点击事件当做动态属性 会进行 diff 算法比较, 但是在事件监听缓存之后就没有静态标记了,就会进行缓存复用
-
-
为什么 vue3.0 体积比 vue2.x 小
- 在 vue3.0 中创建 vue 项目 除了 vue-cli,webpack 外还有 一种创建方法是 Vite Vite 是作者开发的一款有意取代 webpack 的工具,其实现原理是利用 ES6 的 import 会发送请求去加载文件的特性,拦截这些请求,做一些预编译,省去 webpack 冗长的打包时间
70.你做过哪些 Vue 的性能优化
-
首屏加载优化
-
路由懒加载
-
开启服务器 Gzip
- 开启 Gzip 就是一种压缩技术,需要前端提供压缩包,然后在服务器开启压缩,文件在服务器压缩后传给浏览器,浏览器解压后进行再进行解析。首先安装 webpack 提供的
compression-webpack-plugin
进行压缩,然后在 vue.config.js:
- 开启 Gzip 就是一种压缩技术,需要前端提供压缩包,然后在服务器开启压缩,文件在服务器压缩后传给浏览器,浏览器解压后进行再进行解析。首先安装 webpack 提供的
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = ['js', 'css']......plugins: [
new CompressionWebpackPlugin({
algorithm: 'gzip',
test: new RegExp('\.(' + productionGzipExtensions.join('|') + ')$'),
threshold: 10240,
minRatio: 0.8
})
]....
-
启动 CDN 加速
- 我们继续采用 cdn 的方式来引入一些第三方资源,就可以缓解我们服务器的压力,原理是将我们的压力分给其他服务器点。
-
代码层面优化
-
computed 和 watch 区分使用场景
- computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
- watch:类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
-
v-if 和 v-show 区分使用场景 v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。这里要说的优化点在于减少页面中 dom 总数,我比较倾向于使用 v-if,因为减少了 dom 数量。
-
v-for 遍历必须为 item 添加 key,且避免同时使用 v-if v-for 遍历必须为 item 添加 key,循环调用子组件时添加 key,key 可以唯一标识一个循环个体,可以使用例如 item.id 作为 key 避免同时使用 v-if,v-for 比 v-if 优先级高,如果每一次都需要遍历整个数组,将会影响速度。
-
-
Webpack 对图片进行压缩
-
避免内存泄漏
-
减少 ES6 转为 ES5 的冗余代码
71. 说一下单页面 应用
通常的 url 地址由以下内容构成:协议名 域名 端口号 路径 参数 哈希值,当哈希值改变,页面不会发生跳转,单页面应用就是利用了这一点,给 window 注册 onhashchange 事件,当哈希值改变时通过 location.hash 就能获得相应的哈希值,然后就能跳到相应的页面。
- hash 通过监听浏览器的 onhashchange()事件变化,查找对应的路由规则
- history 原理: 利用 H5 的 history 中新增的两个 API pushState() 和 replaceState() 和一个事件 onpopstate 监听 URL 变化
72.Vue 路由实现的底层原理
-
在 Vue 中利用数据劫持 defineProperty 在原型 prototype 上初始化了一些 getter,
- 分别是 router 代表当前 Router 的实例.
- route 代表当前 Router 的信息。
-
在 install 中也全局注册了 router-view, router-link, 其中的 Vue.util.defineReactive, 这是 Vue 里面观察者劫持数据的方法,劫持 _route,当 _route 触发 setter 方法的时候,则会通知到依赖的组件。
-
接下来在 init 中,会挂载判断是路由的模式,是 history 或者是 hash,点击行为按钮,调用 hashchange 或者 popstate 的同时更_route, _route 的更新会触发 route-view 的重新渲染。
73.用过插槽吗?用的是具名插槽还是匿名插槽
- 用过,都使用过。插槽相当于预留了一个位置,可以将我们书写在组件内的内容放入,写一个插槽就会将组件内的内容替换一次,两次则替换两次。为了自定义插槽的位置我们可以给插槽取名,它会根据插槽名来插入内容,一一对应。
- 举例来说,这里有一个 组件,可以像这样使用:
<FancyButton>
Click me!
<!-- 插槽内容 -->
</FancyButton>
- 而 的模板是这样的:
<button class="fancy-btn">
<slot></slot>
<!-- 插槽出口 -->
</button>