0.null和undefined区别
- null表示"没有对象",即该处不应该有值,典型用法是: (1) 作为函数的参数,表示该函数的参数不是对象。 (2) 作为对象原型链的终点。
- undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是: (1)变量被声明了,但没有赋值时,就等于undefined。 (2 ) 调用函数时,应该提供的参数没有提供,该参数等于undefined。 (3)对象没有赋值的属性,该属性的值为undefined。 (4)函数没有返回值时或者return后面什么也没有,返回undefined
1.闭包
- 闭包就是能够读取其他函数内部变量的函数
- 可以把闭包简单理解成“定义在一 个函数内部的函数”。
- 不能滥用闭包,会造成网页的性能问题。 IE 中可能导致内存泄露
2.call和apply的区别
- call改变 this 的指向,第一个参数是 this 的指向,从第二个参数开始是以 逗号分隔的不定参数,立即执行
- apply 改变 this 的指向,第一个参数是 this 的指向,第二个参数是数组, 立即执行
3.cookies,sessionStorage,localStorage 的区别?
- 存储大小限制也不同,cookie 数据不能超过 4K,同时因为每次 http 请求 都会携 带 cookie
- 数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭之前有效; localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据; cookie:只在设置的 cookie 过期时间之前有效,即使窗口关闭或浏览器关闭
- 作用域不同,sessionStorage 不在不同的浏览器窗口中共享,即使是同一 个页面;localStorage 在所有同源窗口中都是共享的;cookie 也是在所有同源窗口中都是共享的
4.浏览器地址栏输入url 发生了什么
- URL 解析
- DNS 查询
- TCP 连接
- 处理请求
- 接受响应
- 渲染页面
5.构造函数和原型函数
[prototype] zhuanlan.zhihu.com/p/213022502
- 通过new操作符来调用的,就是构造函数
- 函数对象的
prototype
指向原型对象,原型对象的constructor
指向函数对象 - 实例对象的
[Protoptype]
属性指向原型对象
6.浏览器适配
- CSS前缀:不同浏览器厂商可能对CSS特性的实现不一致,需要使用相应的CSS前缀来适配。例如,-webkit-前缀适用于Safari和Chrome,-moz-前缀适用于Firefox,-o-前缀适用于Opera。
- JavaScript特性:不同浏览器对JavaScript特性的实现也可能有差异,需要检测特性是否被支持并提供替代方案。例如,某些浏览器不支持ES6语法,需要使用Babel等工具将代码转换为ES5语法。
- 浏览器兼容性:需要考虑不同浏览器的版本,不同版本可能会有不同的特性支持和bug修复。可以使用Can I Use等网站查询特定浏览器版本的支持情况。
7.ES6 Map与Set
-
Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
-
Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
-
Map
-
key可以是字符串、对象、函数、NaN
var myMap = new Map(); var keyString = "a string"; myMap.set(keyString, "和键'a string'关联的值"); myMap.get(keyString); // "和键'a string'关联的值" myMap.get("a string"); // "和键'a string'关联的值" // 因为 keyString === 'a string'
-
Map的迭代
- 1.for...of
for (var [key, value] of myMap) { console.log(key + " = " + value); } for (var [key, value] of myMap.entries()) { console.log(key + " = " + value); } /* 这个 entries 方法返回一个新的 Iterator 对象,它按插入顺序包含了 Map 对象中每个元素的 [key, value] 数组。 */ for (var key of myMap.keys()) { console.log(key); } for (var value of myMap.values()) { console.log(value); }
-
Map的迭代
-
forEach()
myMap.forEach(function(value, key) { console.log(key + " = " + value); }, myMap)
-
-
- Set
let mySet = new Set();
mySet.add(1); // Set(1) {1}
mySet.add(5); // Set(2) {1, 5}
mySet.add(5); // Set(2) {1, 5} 这里体现了值的唯一性
mySet.add("some text");
// Set(3) {1, 5, "some text"} 这里体现了类型的多样性
var o = {a: 1, b: 2};
mySet.add(o);
mySet.add({a: 1, b: 2});
// Set(5) {1, 5, "some text", {…}, {…}}
// 这里体现了对象之间引用不同不恒等,即使值相同,Set 也能存储
8.async和await
async/await
是promise
的语法糖,作用是为了让Promise
更加完善,让代码看上去更加同步promise.all
和promise.race
是为了解决多个解决(异步的结果)async
就是为了标记function
,其它没啥用- 所有
async
都会返回一个promise
await
只能放在async函数
里面- 错误捕获使用
try...catch...
10.ES6的新特性
- 1.不一样的变量声明:const和let
- 2.模板字符串
- 3.箭头函数(Arrow Functions)
- 4.函数的参数默认值
- 5.对象和数组解构
11.前端性能优化
-
优化模块
- 减少HTTP请求
- 白屏时间做加载动画
-
资源
-
静态资源cdn
静态css/js/img等资源可以做cdn缓存,这样把资源同步到全国全球各地,用户就能更快访问到
-
gzip压缩
服务端配置,如nginx可配置支持gzip压缩资源传输的方式
-
将CSS放在文件头部,JavaScript文件放在底部
单线程js可能会阻滞文档加载
-
-
图片
-
字体图标代替图片图标
-
精灵图
-
图片懒加载
为了首屏渲染更快,图片可设置一张加载图代替,当页面在可视区域内时在替换为正真的图片
-
图片预加载
可以在window.onload之后请求一些其他地方需要的图片资源
-
小于10k的图片可以打包为base64格式
可以使用webpack url-loader处理
-
-
代码
-
慎用全局变量
-
缓存全局变量
将使用中无法避免的全局变量缓存到局部
-
节流、防抖
-
少用闭包、减少内存泄漏
-
-
webpack优化
- 减小代码体积
- 按需加载
- 提取第三方库
12.for in与for of的区别
-
主要区别在于迭代对象和迭代方式
1.迭代对象:
-
for-in
循环用于迭代对象的可枚属性。它会迭代对象的所有可举属性,包括继承的属性。它适用于迭代普通对象和数组等可迭代对象。但需要注意的是,for-in
循环可能会遍历到一些非预期的属性,例如原型链上的属性和一些内置属性 -
for-of
循环用于迭代可迭代对象(例如数组、字符串、Set、Map等)。它会迭代对象的迭代器的返回值。for-of
循环不会迭代对象的属性,只能迭代实际的值。它遍历的是对象自身的属性,不包括继承的属性2.迭代方式
-
for-in
循环通过遍历对象的键来进行迭代。在每次迭代中,变量会被赋值为当前迭代的键 -
for-of
循环通过遍历对象的值来进行迭代。在每次迭代中,变量会被赋值为当前迭代的值
12.1 forEach和map的区别
- 都是循环遍历数组中的每一项
- 每一次执行匿名函数都支持三个参数,数组中的当前项item,当前项的索引index,原始数组input
- 匿名函数中的this都是指window
-
map
- 有返回值,可以return出来一个length和原数组一致的数组(内容可能包含undefined、null等)
-
forEach
- 被调用时,不会改变原数组,也就是调用它的数组(尽管 callback 函数在被调用时可能会改变原数组)
- forEach没有返回值,返回结果为undefined
13.什么是前端跨域问题以及如何解决跨域问题
-
什么是前端的跨域问题
- 浏览器的同源策略限制了网页不能加载其他源(域名、协议、端口)的资源
-
同源策略的限制包括以下几个方面:
- Cookie、LocalStorage 和 IndexDB 等存储机制。不同站点的 Cookie、LocalStorage、IndexDB 是独立的,无法相互获取。
- DOM 和 JS 对象。JS脚本只能访问同源页面的对象和方法,而不能访问不同源的对象和方法。
- AJAX 请求。AJAX请求的限制也是基于同源策略的。使用XHR对象发送AJAX请求时,浏览器会根据请求URL的源与当前页面的源是否相同来决定是否发送该请求。
-
如何解决跨域
- 使用JSONP(JSON with Padding)技术。JSONP是一种跨域访问资源的方式,它利用了script标签不受同源策略限制的特性,将JSON数据作为参数传递到一个回调函数中,并将该函数作为一个脚本动态插入到页面中。
- 使用CORS(Cross-origin Resource Sharing)技术。该技术通过在原生XHR对象上使用标准的HTTP头部来允许浏览器和服务器进行跨源通信,从而实现安全的跨域数据传输。
- 使用代理。将跨域请求发送到同源的服务器上,由该服务器向目标服务器请求数据,并将数据返回给页面,从而避免了跨域问题。
14.GET和POST有什么区别
- 数据传输方式不同:GET 请求通过 URL 传输数据,而 POST 的数据通 过请求体传输
- 安全性不同:POST 的数据因为在请求主体内,所以有一定的安全性保 证,而 GET 的数据在 URL 中,通过历史记录,缓存很容易查到数据信息。
- 数据类型不同:GET 只允许 ASCII 字符,而 POST 无限制
- 特性不同:GET 是安全(这里的安全是指只读特性,就是使用这个方法 不会引起服务器状态变化)且幂等(幂等的概念是指同一个请求方法执行多次和 仅执行一次的效果完全相同),而 POST 是非安全非幂等
15.原型和原型链
- 原型:所有的函数默认都有一个“prototype”这样公有且不可枚举的属性,它会指向另一个对象,这个对象就是原型
- 原型链:当访问对象的属性或方法时,首先对象会从自身去找,找不到就会往原型中去找,也就是它构造函数的“prototype”中,如果原型中找不到,即构造函数中也没有该属性,就会往原型后面的原型上去找, 这样逐层深入直到顶层对象Object的原型对象 ,就形成了链式的结构,称为原型链(prototype chain)
16.JS事件循环
- 同一层级同一个任务体里面,先执行同步代码然后微任务最后才是宏任务,但执行宏任务的时候需要观察其他任务体里面的同步代码和微任务,如果有要先执行
- new Promise()属于宏任务,而new Promise().then则属于微任务;setTimeout属于宏任务
- 1.JS是从上到下一行一行执行。
- 2.如果某一行执行报错,则停止执行下面的代码。
- 3.先执行同步代码,再执行异步代码
//下面的代码中 setTimeout受第二个参数(时间)的影响
<script>
setTimeout(() => {
console.log("定时器1");//执行顺序6 同步代码
new Promise((resolve) => {
console.log("promsie3"); //执行顺序7 宏任务
resolve()
}).then(() => {
console.log("promise3.then");//执行顺序8 微任务
})
setTimeout(() => {
console.log("定时器3"); //执行顺序10 宏任务
}, 0)
}, 0)
new Promise((resolve) => {
console.log("promise1"); //执行顺序1 同步代码
resolve()
}).then(() => {
console.log("promise1.then");//执行顺序3 微任务
setTimeout(() => {
console.log("定时器2");//执行顺序9 宏任务
}, 0)
new Promise(resolve => {
console.log("promise2");//执行顺序4 宏任务
resolve()
}).then(() => {
console.log("promise2.then"); //执行顺序5 微任务
})
})
console.log("some code");//执行顺序2 同步代码
</script>
17.JS的基本类型
- Number 、String、Boolean、Null、Undefined、Symbol
18.箭头函数和普通函数的区别
- 箭头函数没有原型 prototype
- call、apply、bind 并不会影响其 this 的指向。
- 箭头函数不能作为构造函数使用,也不能使用 new 关键字
- 箭头函数会捕获其所在上下文的 this 值,作为自己的 this 值,定义的时候就确定并固定了
19.new 操作符到底做了什么
- 创建一个空的对象;
- 让空对象的原型属性指向原型链;
- 让构造函数的 this 指向 obj,并执行函数体;
- 判断返回类型,如果是值就返回这个 obj,如果是引用类型,返回这个 引用对象。
20.一些JS数据类型的判断结果
typeof NaN // number
typeof null //object
typeof undefined //undefined
typeof [] //object
typeof {} //object
typeof Function //function
null instanceof Object //false
null == undefined //false
null === undefined //false
null == NaN //false
null === NaN //false
NaN == NaN //false
NaN === NaN //false
null == undefined //true
21.HTTP状态码
-
成功响应
- 200 OK 请求成功
-
重定向消息
- 301 请求资源的URL已永久更改
- 304 缓存
-
客户端错误响应
- 400 错误的请求(错误的请求语法、无效的请求消息帧)
- 401 未授权
- 403 无权限
- 404 服务器知道请求方法,但目标资源不支持该方法
-
服务器响应错误
- 500 服务器遇到了不知道如何处理的情况
- 502 表明服务器作为网关需要得到一个处理这个请求的响应,但是得到一个错误的响应
- 503 服务器未准备好处理请求
- 504 网关超时
- 505 服务器不支持请求中使用的HTTP版本
22.前端的常见构建工具
-
总结
- webpack更适合打包项目
- vite基于rollup实现了热更新也适合打包项目
- rollup更适合打包库(没有webpack这么多的工具函数,rollup不支持热更新,不适合开发应用使用,因为需要使用第三方模块)
- esbuild更适合作为底层的模块构建工具(其编译阶段就已经将源码转译为了机器码)
-
webpack和vite(含有一个开发服务器、一套构建指令)两者比较:
Vite启动更快是因为webpack启动时需要加载全部的资源文件再启动服务,而vite则会优先启动服务器再按需加载需要的资源
-
详情介绍
-
webpack
webpack是一个用于现代 JavaScript 应用程序的静态模块打包工具(将项目中用到的文件全部转换为JS文件)
1、优势
- 可以将各种资源文件视为模块进行处理和打包,并自动识别依赖关系
- 拥有强大的插件系统、实现对代码压缩、分包chunk、模块热更新等
- 支持自定义配置文件
- 提供了各种插件和加载器处理各种资源文件
2、劣势
- 构建速度较慢
- 体积较大
- 配置复杂
-
rollup
相比于Webpack,Rollup要小巧的多,打包生成的文件更小
1、优势
- 没有webpack那么多工具函数,因此打包产物比较干净,体积小
- 插件机制设计得相对更干净简洁
2、劣势
- rollup不支持热更新
- 不适合开发应用使用,因为需要使用第三方模块
-
vite
一个开发服务器、一套构建指令(使用rollup打包代码)
1、优势
- 快速的冷启动:vite会直接启动开发服务器,不需要进行打包操作,所以不需要分析模块的依赖、不需要编译,因此启动速度非常快。
- 即时的热更新:在热模块HMR方面,当修改一个模块的时候,仅需让浏览器重新请求该模块即可,无须像webpack那样需要把该模块的相关依赖模块全部编译一次,效率更高。
- 真正的按需编译:利用现代浏览器支持ES Module的特性,当浏览器请求某个模块的时候,再根据需要对模块的内容进行编译,这种方式大大缩短了编译时间
- 更小的打包体积,vite在生产环境通过rollup进行打包,打包产物体积小。
- 更加的简单易用,相对于 Webpack 来说,Vite 的配置更加简单明了,许多默认配置已经足够满足大多数前端项目的需求。
2、劣势
- 对于旧浏览器支持较差,由于 Vite 采用了 ES 模块化和原生浏览器 APIs,因此在旧版本的浏览器中可能会出现兼容性问题。
-
esbuild
一个非常新的模块打包工具,拥有着超高的性能
1、优势
- 编译速度非常快,相比其他流行的 JavaScript 编译器和打包器,esbuild基于Go语言编写,在编译阶段就已经将源码转译为机器码,所以速度最多可以快 100 倍。
- esbuild 支持多种模块格式,包括 CommonJS、ES6 模块、AMD 等,使得它适用于任何类型的 JavaScript 项目。
- esbuild 的配置非常简单,只需要提供一个入口文件和输出目录即可。
2、劣势
- 支持不完善,提供的功能很基础,对代码分割和css处理等支持较弱。
- 配置灵活的不高,侧重于快速且轻量级的构建,没有提供一些复杂的插件或高级配置选项。
- 没有稳定版本,不适合直接用到生产环境,
23.数组方法sort
- sort默认排序是将元素转换为字符串,然后按照它们的 UTF-16 码元值升序排序
24.浏览器回收机制
-
1.标记清理
- 标记在上下文中的变量,若变量不在上下文中则标记不在上下文中
- 思路:垃圾回收会周期性的运行,运行过程中会标记内存中所有的变量,然后再对被引用的变量移除标记,剩下的被标记的变量就是会被销毁回收的
-
2.引用计数
-
思路:对每个变量记录引用次数,引用一次(例如变量赋值、变量赋其他值)次数就会加一
如果引用变量的值被覆盖,则引用数减1
-
-
3.V8引擎的垃圾清理策略,分代垃圾回收
-
新生代采用Scavenge算法,存储存活时间短点对象
思路:新对象会在From空间分配内存,等到垃圾清理时,把还存活的对象复制到To空间,复制完成后,To空间变为From空间,From空间变为To空间,互相交换
-
老生代采用标记整理算法,存储存活时间较长的对象。
思路:标记和整理
-
25.AJAX工作原理
- 相当于在用户和服务器之间加了一个中间层(AJAX引擎),使用户操作与服务器响应异步化。
其核心通过XMLHttpRequest对象向服务器发异步请求,从服务器获得数据,再用JavaScript来操 作Dom而更新页面
-
具体步骤:
- 1.创建XHR对象;
- 2.调用open()方法创建请求;
- 3.调用send()方法发送请求;
- 4.OnreadyChange捕获状态码;
- 5.判断状态码是否成功;
- 6.调用ajax的response属性返回数据;
26.管理系统权限的控制
-
路由权限
- 在登录请求中会得到权限的数据。前端根据权限去动态生成路由,只允许用户访问权限内的路由,如果通过地址栏去访问权限外的路由会重定向至
404
页面(无论登录了还是没登录)。
- 在登录请求中会得到权限的数据。前端根据权限去动态生成路由,只允许用户访问权限内的路由,如果通过地址栏去访问权限外的路由会重定向至
-
按钮权限
- 同一页面还可能因为权限不同展示不同的按钮。
-
请求和响应的控制
- 如果用户通过非常规操作,比如通过浏览器调试工具将某些禁用的按钮变成启用状态。此时发的请求,也应该被前端所拦截。
-
获取权限信息的方式
-
方式1
- 后端返回权限表或路由表(常见于管理员可以添加新角色)
- 数据结构大概如下
{ "data": { "id": 1, "username": "admin", "token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTY1MzM1NzIyNH0.1y-Ucq_MfFRloesg0eA9pfk-VA3pV_zAOSj3HFpnKak" }, "rights": [ { "id": 125, "authName": "用户管理", "icon": "icon-user", "children": [ { "id": 110, "authName": "用户列表", "path": "users", "rights": ["view","edit","add","delete"] } ] }, { "id": 103, "authName": "角色管理", "icon": "icon-juese", "rights": ["view","edit","add","delete"] } ] }
-
方式2
- 后端返回角色
{ "data": { "id": 1, "username": "admin", "token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTY1MzM1NzIyNH0.1y-Ucq_MfFRloesg0eA9pfk-VA3pV_zAOSj3HFpnKak", "roles": ['admin','editr'] } }
-
方式3
- 前端根据用户信息判断角色
- 如利用level字段
{ "data": { "id": 1, "username": "admin", "token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTY1MzM1NzIyNH0.1y-Ucq_MfFRloesg0eA9pfk-VA3pV_zAOSj3HFpnKak", "level": 1, "units": { "id": 1, "name": "部门1" } } }
-
27.sass中的循环语句
-
@for指令
@for
指令可以用于循环生成样式,@for
指令有两种类型,如下所示:- 其中
$i
表示变量,start
表示起始值,end
表示结束值。其实这两种方式的区别就在于,使用关键字through
时会包括end
这个数,而使用关键字to
则不会包括end
这个数。 (使用through会包含end,而to不会) -
// 第一种 @for $i from <start> through <end> // 第二种 @for $i from <start> to <end> //示例: @for $i from 1 through 3{ .width#{$i} { width: $i * 10px; } }
-
@while指令
@while
指令也可以用于循环样式,后面接 SassScript 表达式,循环会一直到表达式的值为false
时停止。-
示例: $num: 12; @while $num < 18 { .f-#{$num} { font-size: #{$num}px; } $num: $num + 2; }
-
@each 指令
@each
指令可以用于遍历一个列表,然后从列表中取出对应的值。-
@each $i in <list> //示例: $list: 5 10 15 20 25; @each $i in $list { .p-#{$i}{ padding: #{$i}px; } }
28.深拷贝和浅拷贝
-
区别
- 浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存。
- 深拷贝:复制并创建一个一模一样的对象,不共享内存,修改新对象,旧对象保持不变。
-
实现
-
浅拷贝:通过
Object.assign()
拷贝 -
深拷贝:
-
采用
递归
的方式来封装实现深拷贝的函数 -
利用JSON对象实现(无法实现对象里面的包含对象的深拷贝)
-
通过jQuery的extend方法
$.extend([deep ], target, object1 [, objectN ])
-
lodash函数实现lodash.cloneDeep()
-
扩展运算符
-
-