目录
1、前端如何优化网站性能?
2、网页从输入网址到渲染完成经历了哪些过程?
3、浏览器缓存:memory cache、disk cache、强缓存协商缓存等概念
4、JS中常见的内存泄漏
5、如何解决跨域问题
6、http和https有何区别?
7、请简要描述margin重合问题,及解决方式
8、谈谈垃圾回收机制方式及内存管理
9、什么叫优雅降级和渐进增强?
10、typeof 与instanceof区别
11、get 和post方式的区别
12、浏览器的内核分别是什么?
13、关于JS事件冒泡与JS事件代理(事件委托)
14、深拷贝、浅拷贝、以及如何实现?
15、箭头函数和普通函数的区别
16、同步和异步的区别
17、浏览器是如何渲染页面的?
18、请解释JSONP的工作原理,以及它为什么不是真正的AJAX
19、Object.assgin()、扩展运算符(三点运算符)的区别
20、介绍一下js的数据类型有哪些,值是如何存储的?
21、map和Object的区别
22、什么是宏任务和微任务,两者有什么区别?
23、GET请求方式的长度限制到底是多少?
24、Cookie,sessionStorage,localStorage解释及其区别
25、async 和 promise 的区别
26、promise有几种状态?如何变化
27、js的数据类型的转换都有哪些?
28、let、const和var区别
29、document.ready和documentonload的区别
30、undefined,null 和 undeclared 有什么区别?
31、call,apply,bind的相同点和区别?
34、原生对象和宿主对象?
35、描述new一个对象的过程?
36、全局函数eval()有什么作用?
37、请解释一下变量声明提升?
38、什么是原型?什么是原型链?
39、js 获取原型的方法?
40、什么是同源策略(Same origin policy)?
41、什么是跨域资源共享(CORS)?
42、什么是跨站请求伪造(CSRF)?
43、什么是跨站攻击(XXS)?
44、for..in 和 object.keys的区别?
45、JS 中 == 和 === 区别是什么?
46、set 和map 的区别?
47、防抖和节流
48、HTTP的几种请求方法用途?
49、require和import之间的区别?
50、Object.is()与比较操作符 "==="、"==”的区别?
51、栈和堆的区别?
52、ES5 和 ES6 分别有几种方式声明变量
52、谈谈你对ES6的理解
53、forEach、for...in 、for...of三者的区别
54、什么是事件流?什么是事件冒泡?什么是事件捕获?
55、响应事件有哪些?
1、前端如何优化网站性能?
1、减少 HTTP 请求数量
在浏览器与服务器进行通信时,主要是通过 HTTP 进行通信。浏览器与服务器需要经过三次握手,每次握手需要花费大量时间。而且不同浏览器对资源文件并发请求数量有限(不同浏览器允许并发数),一旦 HTTP 请求数量达到一定数量,资源请求就存在等待状态,这是很致命的,因此减少 HTTP 的 请求数量可以很大程度上对网站性能进行优化。
CSS Sprites:国内俗称CSS精灵,这是将多张图片合并成一张图片达到减少HTTP请求的一种解决方案,可以通过CSS的background属性来访问图片内容。这种方案同时还可以减少图片总字节数。
合并 CSS 和 JS 文件: 现在前端有很多工程化打包工具,如:grunt、gulp、webpack等。为了减少 HTTP 请求数量,可以通过这些工具再发布前将多个CSS或者多个JS合并成一个文件。
采用 lazyLoad: 俗称懒加载,可以控制网页上的内容在一开始无需加载,不需要发请求,等到用户操作真正需要的时候立即加载出内容。这样就控制了网页资源一次性请求数量。
2、控制资源文件加载优先级
浏览器在加载HTML内容时,是将HTML内容从上至下依次解析,解析到link或者script标签就会加载href或者src对应链接内容,为了第一时间展示页面给用户,就需要将CSS提前加载,不要受 JS 加载影响。
一般情况下都是CSS在头部,JS在底部。
3、利用浏览器缓存
浏览器缓存是将网络资源存储在本地,等待下次请求该资源时,如果资源已经存在就不需要到服务器重新请求该资源,直接在本地读取该资源。
4、减少重排(Reflow)
基本原理:重排是DOM的变化影响到了元素的几何属性(宽和高),浏览器会重新计算元素的几何属性,会使渲染树中受到影响的部分失效,浏览器会验证 DOM 树上的所有其它结点的visibility属性,这也是Reflow低效的原因。如果Reflow的过于频繁,CPU使用率就会急剧上升。
减少Reflow,如果需要在DOM操作时添加样式,尽量使用 增加class属性,而不是通过style操作样式。
5、减少 DOM 操作
6、图标使用 IconFont 替换
2、网页从输入网址到渲染完成经历了哪些过程?
大致可以分为如下7步:
输入网址;
发送到DNS服务器,并获取域名对应的web服务器对应的ip地址;
与web服务器建立TCP连接;
浏览器向web服务器发送http请求;
web服务器响应请求,并返回指定url的数据(或错误信息,或重定向的新的url地址);
浏览器下载web服务器返回的数据及解析html源文件;
生成DOM树,解析css和js,渲染页面,直至显示完成;
3、浏览器缓存:memory cache、disk cache、强缓存协商缓存等概念
从缓存位置上来说分为四种:
1、memory cache:
Memory Cache 也就是内存中的缓存
优点:
读取速度快
缺点:
一旦我们关闭 Tab 页面,内存中的缓存也就被释放了。
如何触发:
当我们访问过页面以后,再次刷新页面,可以发现很多数据都来自于内存缓存
2、disk cache(css等是disk cache):
Disk Cache 也就是存储在硬盘中的缓存
优点:
缓存再硬盘中,容量大
缺点:
读取速度慢
如何触发:
根据浏览器请求头
3、Service Worker:
Service Worker 是运行在浏览器背后的独立线程,一般可以用来实现缓存功能。
传输协议必须为 HTTPS
Service Worker 的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。
4、Push Cache:
Push Cache(推送缓存)是 HTTP/2 中的内容,当以上三种缓存都没有命中时,它才会被使用。
它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂
强缓存:
不会向服务器发送请求,直接从缓存中读取资源。
在chrome控制台的Network选项中可以看到该请求返回200的状态码,并且Size显示from disk cache或from memory cache。
强缓存可以通过设置两种 HTTP Header 实现:Expires 和 Cache-Control。
1、Expires
缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。
2、Cache-Control
比如:Cache-Control:max-age=300 时,则代表在这个请求正确返回的5分钟内再次加载资源,就会命中强缓存。
注意:如果max-age和Expires同时存在,则被Cache-Control的max-age覆盖
3、max-age
web中的文件被用户访问(请求)后的存活时间,是个相对的值,相对Request_time(请求时间)
4、last-modified
WEB 服务器认为对象的最后修改时间,比如文件的最后修改时间,动态页面的最后产生时间
5、ETag
对象(比如URL)的标志值,就一个对象而言,文件被修改,Etag也会修改
三级缓存原理
1. 先去内存看,如果有,直接加载
2. 如果内存没有,择取硬盘获取,如果有直接加载
3. 如果硬盘也没有,那么就进行网络请求
4. 加载到的资源缓存到硬盘和内存
比如:访问图片-> 200 -> 退出浏览器
再进来-> 200(from disk cache) -> 刷新 -> 200(from memory cache)
4、JS中常见的内存泄漏
1、意外的全局变量
函数中意外的定义了全局变量,每次执行该函数都会生成该变量,且不会随着函数执行结束而释放。
2、未清除的定时器
定时器没有清除,它内部引用的变量,不会被释放。
3、脱离DOM的元素引用
一个dom容器删除之后,变量未置为null,则其内部的dom元素则不会释放。
4、持续绑定的事件
函数中addEventListener绑定事件,函数多次执行,绑定便会产生多次,产生内存泄漏。
5、闭包引起内存泄漏
比如事件处理回调,导致DOM对象和脚本中对象双向引用。
6、console.log
console.log的对象是不能被垃圾回收
5、如何解决跨域问题
(1)通过jsonp跨域
(2)document.domain + iframe跨域
(3)location.hash + iframe
(4) window.name + iframe跨域
(5)postMessage跨域
(6)跨域资源共享(CORS)
(7)nginx代理跨域
(8)nodejs中间件代理跨域
(9)WebSocket协议跨域
6、http和https有何区别?
http是HTTP协议运行在TCP之上。所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份。
https是HTTP运行在SSL/TLS之上,SSL/TLS运行在TCP之上。所有传输的内容都经过加密,加密采用对称加密,但对称加密的密钥用服务器方的证书进行了非对称加密。
此外客户端可以验证服务器端的身份,如果配置了客户端验证,服务器方也可以验证客户端的身份。
7、请简要描述margin重合问题,及解决方式
(1)设置padding代替margin
(2)设置float
(3)设置overflow
(4)设置position:absolute 绝对定位
(5)设置display: inline-block
8、谈谈垃圾回收机制方式及内存管理
JavaScript 在定义变量时就完成了内存分配。当不在使用变量了就会被回收,因为其开销比较大,垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。
(1)垃圾回收
标记清除法
当变量进入环境时,将这个变量标记为'进入环境'。当标记离开环境时,标记为‘离开环境’。离开环境的变量会被回收
引用技计数法
跟踪记录每个值被引用的次数,如果没有被引用,就会回收
(2)内存管理
内存分配=》内存使用=》内存回收
9、什么叫优雅降级和渐进增强?
渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。
优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。比如一开始使用 CSS3 的特性构建了一个应用,然后逐步针对各大浏览器进行 hack 使其可以在低版本浏览器上正常浏览。
其实渐进增强和优雅降级并非什么新概念,只是旧的概念换了一个新的说法。在传统软件开发中,经常会提到向上兼容和向下兼容的概念。渐进增强相当于向上兼容,而优雅降级相当于向下兼容。
区别:优雅降级是从复杂的现状开始,并试图减少用户体验的供给,而渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要。降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带
10、typeof 与instanceof区别
typeof与instanceof都是判断数据类型的方法,区别如下:
typeof会返回一个变量的基本类型,instanceof返回的是一 个布尔值
instanceof可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型
而typeof也存在弊端,它虽然可以判断基础数据类型(null 除外),但是引用数据类型中,除了function类型以外,其他的也无法判断
11、get 和post方式的区别
(1)get请求不安全;post安全 ;
(2)get请求数据有大小限制,受浏览器url长度的限制;post无限制;
(3)get请求参数会在url中显示,容易被他人窃取;post在请求体中,不会被窃取;
(4)post需要设置请求头;
(5)get是从服务器上获取数据;post是想服务器传送数据;
12、浏览器的内核分别是什么?
(1)Mozilla Firefox的Gecko
(2)Chrome的Blink(WebKit的分支)
(3)Opera的内核原为Presto,现为Blink
(4)IE的内核Trident
(5)Safari的内核WebKit
13、关于JS事件冒泡与JS事件代理(事件委托)
(1)事件冒泡
当一个元素接收到事件的时候 会把他接收到的事件传给自己的父级,一直到window,过程就像冒泡泡 。如果在某一层想要中止冒泡,使用 event.stopPropagation() 。
但是当大量标签大量事件的时候显然不可能为每个元素都加上事件,(事件绑定占用事件,浏览器要跟踪每个事件,占用更多内存。而且并不是所有事件都会被用户使用到)。所以需要事件委托来解决这个问题。
(2)事件委托
将事件给最外层的元素,自己不实现逻辑,由最外层元素来代理。(判断事件源,做不同处理)
14、深拷贝、浅拷贝、以及如何实现?
深拷贝和浅拷贝都是针对复杂类型来说的,深拷贝式是层层拷贝,浅拷贝是只拷贝一层。
浅拷贝:使用object.assign、直接用=赋值只拷贝地址,它是将数据中的所有数据引用下来,指向同一个存放地址,拷贝后的数据修改后,会影响到原数据中的对象数据。
深拷贝:JSON.parse(JSON. stringify...),递归拷贝每一层对象是内容拷贝,将数据中的所有数据都拷贝下来,对拷贝后的数据进行修改,不会影响到原数据。
可以使用for...in、扩展运算符...、递归等递归函数实现深拷贝
递归:递归就是一个函数调用其本身,通过栈来实现。每执行一个函数,就新建一个函数栈。
15、箭头函数和普通函数的区别
(1)普通函数
可以通过bind、call、apply改变this指向
可以使用new
(2)箭头函数
本身没有this指向,
它的this在定义的时候继承自外层第一个普通函数的this
被继承的普通函数的this指向改变,箭头函数的this指向会跟着改变
箭头函数外层没有普通函数时,this指向window
不能通过bind、call、apply改变this指向
使用new调用箭头函数会报错,因为箭头函数没有constructor
16、同步和异步的区别
同步是一直阻塞模式,如果一个请求需要等待回调,那么会一直等待下去,直到返回结果
异步是非阻塞模式,无需等待回调,可执行下一步的代码
17、浏览器是如何渲染页面的?
渲染的流程如下:
1.解析HTML文件,创建DOM树。
自上而下,遇到任何样式(link、style)与脚本(script)都会阻塞(外部样式不阻塞后续外部脚本的加载)。
2.解析CSS。优先级:浏览器默认设置<用户设置<外部样式<内联样式<HTML中的style样式;
3.将CSS与DOM合并,构建渲染树(Render Tree)
4.布局和绘制,重绘(repaint)和重排(reflow)
18、请解释JSONP的工作原理,以及它为什么不是真正的AJAX
JSONP 是一种非正式传输协议,允许用户传递一个callback给服务端,然后服务端返回数据时会将这个callback 参数作为函数名来包裹住 JSON 数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
当GET请求从后台页面返回时,可以返回一段JavaScript代码,这段代码会自动执行,可以用来负责调用后台页面中的一个callback函数。
为什么它不是真正的Ajax:
它们的实质不同
ajax的核心是通过xmlHttpRequest获取非本页内容
jsonp的核心是动态添加script标签调用服务器提供的js脚本
jsonp只支持get请求,ajax支持get和post请求
19、Object.assgin()、扩展运算符(三点运算符)的区别
Object.assgin()是浅拷贝
三点运算符第一层是深拷贝,其他的都是浅拷贝
20、介绍一下js的数据类型有哪些,值是如何存储的?
(1)数据类型
基本数据类型:Number、Boolean、null、undefined、Symbol(ES6新增,表示独一无二的值)和Bigint(ES10新增)
引用数据类型:Object
(2)如何存储
原始数据类型:直接存储在栈中,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储。
引用数据类型:同时存储在栈和堆中,占据空间大,大小不固定。引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
21、map和Object的区别
(1)意外的键:Map默认不包含任意键,只包含插入的键值;Object有一个原型、原型链的键名可能和自己在对象上设置的键名发生冲突;
(2)键的类型:Map键的类型是任意的;Object键的类型是string和symbol;
(3)键的顺序:Map有序的,迭代的时候以其插入的顺序返回键值;Object无序的;
(4)size:Map的长度可以通过size属性获取;Object需要手动计算;
(5)迭代:Map是可迭代的;Object需要通过获取键来迭代;
(6)性能:Map在频繁增删键值对的场景下表现更好;Object在频繁添加和删除键值对的场景下未作出优化;
22、什么是宏任务和微任务,两者有什么区别?
整个JS在运行过程中主要执行以下事件循环(Even loop):
主程序从上往下执行同步任务
异步任务会被放入异步任务队列中
当同步任务执行完成后,会去异步任务队列中执行异步事件
在异步任务中还有宏任务和微任务的区别:
宏任务:setTimeout、setInterval、Ajax、DOM事件等
微任务:promise、async/await、Object.observe等
宏任务和微任务的执行顺序:
同步任务->微任务->宏任务
两者的区别:
宏任务:DOM渲染后触发,如setTimeout
微任务:DOM渲染前触发,如promise
23、GET请求方式的长度限制到底是多少?
误区:我们经常以为GET请求参数的大小存在限制,而POST请求参数大小的无限制的
实际上HTTP协议从没有规定GET/POST的请求长度显示是多少。对GET请求参数的限制是来源于浏览器或者web服务器,浏览器或web服务器限制了url的长度。对POST请求起限制作用的是服务器处理程序的处理能力。
再次强调:
HTTP 协议 未规定 GET 和 POST 的长度限制
GET 的最大长度显示是因为浏览器和 web 服务器限制了 URL 的长度
不同的浏览器和 WEB 服务器,限制的最大长度不一样
要支持 IE,则最大长度为 2083 byte,若只支持 Chrome,则最大长度 8182 byte
补充各大浏览器对url的最大长度限制:
Firefox:对Firefox浏览器URL的长度限制为:65536个字符。
Safari:URL最大长度限制为80000个字符。
Opera:URL最大长度限制为190000个字符。
Google(chrome):URL最大长度限制为8182个字符。
Apache(Server):能接受的最大url长度为8192个字符
Microsoft Internet Information Server(IIS):n能接受最大url的长度为16384个字符。
注意:(若长度超限,则服务端返回414标识)
24、Cookie,sessionStorage,localStorage解释及其区别
(1)Cookie
Cookie 是一些数据,由服务器生成,发送给浏览器,一旦用户从该网站或服务器退出,Cookie 就存储在用户本地的硬盘上,下一次请求同一网站时会把该cookie发送给服务器。Cookie的作用就是用于解决“如何记录客户端的用户信息”。
可以使用 document.cookie 属性来创建 、读取、及删除 cookie。
cookie的内容主要包括:名字name,值value,过期时间expires,路径path和域domain。路径和域一起构成cookie的作用范围。一般cookie储存在内存里,若设置了过期时间则储存在硬盘里,浏览器页面关闭也不会失效,直到设置的过期时间后才失效。若不设置cookie的过期时间,则有效期为浏览器窗口的会话期间,关闭浏览器窗口就失效。
(2)sessionStorage
sessionStorage顾名思义,是在当前会话下有效,引入了一个“浏览器窗口的概念”,sessionStorage是在同源的同窗口中,始终存在的数据,只要浏览器不关闭,即使是刷新或者进入同源的另一个页面,数据仍在。同时打开“独立”的窗口,即使是同一个页面,sessionStorage的对象也是不同的。关闭窗口后sessionStorage就会被销毁。
可以使用 sessionStorage.setItem、sessionStorage.getItem、sessionStorage.removeItem 来创建 、读取、及删除 sessionStorage。
(3)localStorage
localStorage的生命周期是永久,除非手动去清除,否则永远都存在,他的储存大小是5MB,仅在客户端浏览器上储存,不参与服务器的通信。
可以使用 localStorage.setItem、localStorage.getItem、localStorage.removeItem 来创建 、读取、及删除 localStorage。
Cookie,sessionStorage,localStorage的区别:
存储大小:Cookie 是4KB,Storage是5M;
有效期:Cookie可以设置有效期,超过有效期自动清除;localStorage永久存储,除非手动清除;sessionStorage是会话缓存,关闭浏览器就会清除;
存储位置:Cookie会发送到服务器端,存储在内存中,Storage只存储在浏览器端;
作用域不同:sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localstorage在所有同源窗口中都是共享的;Cookie也是在所有同源窗口中都是共享的
存储内容: Cookie只能保存字符串类型,以文本的方式。Storage通过能支持任何类型的对象(Storage中可含有多个对象)
API:Storage的API接口使用更方便
25、async 和 promise 的区别
(1)Async/Await 代码看起来简洁一些,使得异步代码看起来像同步代码
(2)async await与Promise一样,是非阻塞的。
(3)async await是基于Promise实现的,可以说是改良版的Promise,它不能用于普通的回调函数。
26、promise有几种状态?如何变化
三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected)
promise的状态只可能从“等待”转到“完成”态或者“拒绝”态,不能逆向转换,同时“完成”态和“拒绝”态不能相互转换
状态的表现:
pending:不会触发then和catch
fulfilled:会触发后续的then
rejected:会触发后续的catch
then正常返回 resolve,如果报错则返回 rejected
catch正常返回 resolve,如果报错则返回 rejected
27、js的数据类型的转换都有哪些?
(1)转为布尔值:调用Boolean()方法
(2)转为数字:调用Number()、parseInt()、parseFloat()方法
(3)转为字符串:调用toString()、String()方法
28、let、const和var区别
(1)var存在变量提升,let和const不存在变量提升机制
(2)var允许重复声明,而let和const不允许重复声明
(3)var不存在暂时性死区,let和const存在暂时性死区
(4)let和const创建的全局变量没有给window设置对应的属性
(5)let和const会产生块级作用域
(6)const声明的同时需要赋值,如果是基础数据类型不能重复赋值,如果是引用数据类型则可以修改内部的值例如对象
29、document.ready和documentonload的区别
(1)ready表示文档结构已经加载完成(不包含图片等非文字媒体文件) ,onload表示页面包含图片等文件在内的所有元素都加载完成。
(2)ready可以多次使用,而onload只能有一个,如果出现多个的话后面的会自动覆盖前面的函数;
30、undefined,null 和 undeclared 有什么区别?
null表示“没有对象”,即该处不应该有值,转为数值时为0典型用法是:
作为函数的参数,示该函数的参数不是对象。
作为对象原型链的终点.
undefined表示"缺少值",就是此处应该有一个值, 但是还没有定义, 转为数值时为NaN。典型用法是:
变量被声明了,但没有赋值时,就等于undefined。
调用函数时,应该提供的参数没有提供,该参数等于undefined。
对象没有赋值的属性,该属性的值为undefined.
函数没有返回值时,默认返回undefined.
undeclared: js语法错误,没有申明直接使用,js无法找到对应的上下文。
31、call,apply,bind的相同点和区别?
相同点:
都是改变this指向的;
第一个参数都是this要指向的对象;
都可以利用后续参数传参;
不同点:
call和bind的参数是依次传参,一一对应的;
但apply只有两个参数,第二个参数为数组;
call和apply都是对函数进行直接调用,而bind方法返回的仍是一个函数;
32、js常见的设计模式
(1)单例模式
(2)工厂模式
(3)构造函数模式
(4)发布订阅者模式
(5)迭代器模式
(6)代理模式
33、如何判断js数据类型?
(1)typeof:可以判断出string,number,boolean,undefined,symbol,function,bigint,但判断 typeof(null) 时值为 'object'; 判断数组和对象时值均为 'object'
(2)instanceof:可以判断一个实例是否属于某种类型,也可以判断一个实例是否是其父类型或者祖先类型的实例
(3)constructor:除了undefined和null之外,其他类型都可以通过constructor来判断。但如果声明了一个构造函数,并且改变了它的原型执行,这种情况下constructor也不能准确判断
(4)Object.prototype.toString:判断一个对象只属于某种内置类型,但不能准确判断一个实例是否属于某种类型
(5)Array.isArray:判断是否为数组
34、原生对象和宿主对象?
原生对象是ECMAScript规定的对象,所有内置对象都是原生对象,比如Array、 Date、 RegExp等;
宿主对象是宿主环境比如浏览器规定的对象,用于完善是ECMAScript的执行环境,比如Document、 Location、Navigator等。
35、描述new一个对象的过程?
(1)创建一个新对象,新对象的隐式原型__proto__指向new的构造函数的显示原型proptotype
(2)改变this指向,将构造函数的作用域赋给新的对象,并且执行构造函数的代码,为新的对象添加属性
(3)返回新的对象(return this)
36、全局函数eval()有什么作用?
eval()只有一个参数,如果传入的参数不是字符串,它直接返回这个参数。如果参数是字符串,它会把字符串当成javascript代码进行编译。如果编译失败则抛出一个语法错误(syntaxError)异常。如果编译成功,则开始执行这段代码,并返回字符串中的最后一个表达式或语句的值,如果最后一个表达式或语句没有值,则最终返回undefined。如果字符串抛出一个异常,这个异常将把该调用传递给eval()。
37、请解释一下变量声明提升?
通过var声明的变量会被提升至作用域的顶端。不仅仅是变量,函数声明也一样会被提升。当同一作用域内同时出现变量和函数声明提升时,变量仍然在函数前面。
38、什么是原型?什么是原型链?
原型:每个构造函数都有一个原型对象,实例化出来的对象都有一个原型,指向的是构造函数的原型对象,原型对象里面有一个指针constructor,指向的是它的构造函数。所有的原型对象都是Object构造函数的实例。它的原型指的就是Object原型对象,在往上找Object原型对象的原型就是null了。所有的构造函数都是function构造函数的实例,所有构造函数的原型指的就是function原型对象。
原型链:当在实例化的对象中访问一个属性时,首先会在该对象内部(自身属性)寻找,如找不到,则会向其__proto__指向的原型中寻找,如仍找不到,则继续向原型中__proto__指向的上级原型中寻找,直至找到或Object.prototype.__proto__为止(值为null),这种链状过程即为原型链。
原型的作用:
1.数据共享 节约内存内存空间
2.实现继承
39、js 获取原型的方法?
(1)Object.getPrototypeOf()
(2)__proto__
(3)constructor.prototype
40、什么是同源策略(Same origin policy)?
同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。
详情请查看:https://learn-anything.cn/same-origin-policy
同源策略的作用:
为了保护用户信息的安全,防止恶意的网络窃取
什么是同源:
端口、域名、协议相同
安全限制具体都阻止了哪些东西不可以被访问:
⽆法读取⾮同源策略下的cookie、localstorage
⽆法解除⾮同源的dom
⽆法向⾮同源的地址发送ajax请求
跨域访问:
跨域访问的解决方案是 CORS!(https://learn-anything.cn/cors)
也可以通过window.postMessage来实现,但不推荐,容易造成安全问题
41、什么是跨域资源共享(CORS)?
CORS,全称Cross-Origin Resource Sharing,是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制,通常由于同域安全策略(the same-origin security policy)浏览器会禁止这种跨域请求。
怎么用CORS:
CORS 可以配合 token 来防止 CSRF(跨站请求伪造) 攻击
42、什么是跨站请求伪造(CSRF)?
跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。
简单的说是攻击者通过伪造用户的浏览器的请求,向一个用户自己曾经认证访问过的网站发送出去,使目标网站接收并误以为是用户的真实操作而去执行命令。常用于盗取账号、转账、发送虚假消息等
CSRF 攻击攻击原理及过程:
(1)用户 C 打开浏览器,访问受信任网站 A,输入用户名和密码请求登录网站 A;
(2)在用户信息通过验证后,网站 A 产生 Cookie 信息并返回给浏览器,此时用户登录网站 A 成功,可以正常发送请求到网站 A;
(3)用户未退出网站 A 之前,在同一浏览器中,打开一个 TAB 页访问网站 B;
(4)网站 B 接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点 A;
(5)浏览器在接收到这些攻击性代码后,根据网站 B 的请求,在用户不知情的情况下携带 Cookie 信息,向网站 A 发出请求。网站 A 并不知道该请求其实是由 B 发起的,所以会根据用户 C 的Cookie 信息以 C 的权限处理该请求,导致来自网站 B 的恶意代码被执行。
如何预防CSRF:
1、提交验证码
在表单中添加一个随机的数字或字母验证码。通过强制用户和应用进行交互。来有效地遏制CSRF攻击。
2、Referer Check
检查假设是非正常页面过来的请求,则极有可能是CSRF攻击。
3、token验证
在 HTTP 请求中以參数的形式添加一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,假设请求中没有 token 或者 token 内容不对,则觉得可能是 CSRF 攻击而拒绝该请求。token必须足够随机。敏感的操作应该使用POST,而不是GET。比如表单提交。
4、在HTTP头中自己定义属性并验证
这样的方法也是使用 token 并进行验证。这里并非把 token 以參数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自己定义的属性里。通过 XMLHttpRequest 这个类,能够一次性给全部该类请求加上 csrftoken 这个 HTTP 头属性。并把 token 值放入当中。这样攻克了上种方法在请求中添加 token 的不便。同一时候,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用操心 token 会透过 Referer 泄露到其它站点中去。
43、什么是跨站攻击(XXS)?
跨站攻击,即Cross Site Script Execution(通常简写为XSS)是指攻击者利用网站程序对用户输入过滤不足,输入可以显示在页面上对其他用户造成影响的HTML代码,从而盗取用户资料、利用用户身份进行某种动作或者对访问者进行病毒侵害的一种攻击方式。
如何预防XXS:
1、HttpOnly防止获取cookie
在cookie中设置了HttpOnly属性,那么通过js脚本将无法读取到cookie信息,这样能有效的防止XSS攻击
2、输入检查(不要相信用户的所有输入)
3、输出检查(存的时候转义或者编码)
44、for..in 和 object.keys的区别?
(1)Object.keys不会遍历继承的原型属性
(2)for...in 会遍历继承的原型属性
45、JS 中 == 和 === 区别是什么?
(1)对于string,number等基础类型,==和===有区别
不同类型间比较,==之比较“转化成同一类型后的值”看“值”是否相等,===如果类型不同,其结果就是不等。
同类型比较,直接进行“值”比较,两者结果一样。
(2)对于Array,Object等高级类型,==和===没有区别
进行“指针地址”比较。
(3)基础类型与高级类型,==和===有区别
对于==,将高级转化为基础类型,进行“值”比较。因为类型不同,===结果为false。
示例:
[] == [] // false
{} == {} // false
null == undefined // true(解释:undefined派生自null,所以返回true)
null === undefined // false
46、set 和map 的区别?
(1)Map是键值对,Set是值的集合,键和值可以是任何的值;
(2)Map可以通过get方法获取值,而set不能因为它只有值,set只能用has来判断,返回一个布尔值;
(3)Set的值是唯一的可以做数组去重,Map由于没有格式限制,可以做数据存储
47、防抖和节流
防抖:n秒后在执行该事件,若在n秒内被重复触发,则重新计时
节流: n秒内只运行一次,若在n秒内重复触发,只有一次生效
48、HTTP的几种请求方法用途?
1、GET方法
发送一个请求来取得服务器上的某一资源
2、POST方法
向URL指定的资源提交数据或附加新的数据
3、PUT方法
跟POST方法很像,也是想服务器提交数据。但是,它们之间有不同。PUT指定了资源在服务器上的位置,而POST没有
4、HEAD方法
只请求页面的首部
5、DELETE方法
删除服务器上的某资源
6、OPTIONS方法
它用于获取当前URL所支持的方法。如果请求成功,会有一个Allow的头包含类似“GET,POST”这样的信息
7、TRACE方法
TRACE方法被用于激发一个远程的,应用层的请求消息回路
8、CONNECT方法
把请求连接转换到透明的TCP/IP通道
49、require和import之间的区别?
(1)require对应导出的方法是module.exports,import对应的方法是export default/export
(2)require 是CommonJs的语法,import 是 ES6 的语法标准。
(3)require是运行运行时加载模块里的所有方法(动态加载),import 是编译的时候调用(静态加载),不管在哪里引用都会提升到代码顶部。
(4)require 是CommonJs的语法,引入的是的是整个模块里面的对象,import 可以按需引入模块里面的对象
(5)require 导出是值的拷贝,import 导出的是值的引用
50、Object.is()与比较操作符 "==="、"==”的区别?
(1)两等号判等,会在比较时进行类型转换;
(2)三等号判等(判断严格),比较时不进行隐式类型转换,(类型不同则会返回false);
(3)Object.is 在三等号判等的基础上特别处理了NaN、-0和+0,保证-0和+0不再相同,但Object.is(NaN, NaN)会返回true。Object.is应被认为有其特殊的用途,而不能用它认为它比其它的相等对比更宽松或严格。
补充:
Object.is() 方法判断两个值是否是相同的值。表示两个参数是否相同的布尔值。
如果下列任何一项成立,则两个值相同:
两个值都是 undefined
两个值都是 null
两个值都是 true 或者都是 false
两个值是由相同个数的字符按照相同的顺序组成的字符串
两个值指向同一个对象
两个值都是数字并且
都是正零 +0
都是负零 -0
都是 NaN
都是除零和 NaN 外的其它同一个数字
使用示例:
Object.is(null,undefined) // false
Object.is(NaN,0/0) // true
Object.is(-0,-0) // true
Object.is(0,-0) // false
Object.is(0,+0) // true
Object.is(-0,+0) // false
NaN == NaN // false
NaN === NaN // false
-0 === +0 // true
51、栈和堆的区别?
(1)申请方式的不同。栈由系统自动分配,而堆是人为申请开辟;
(2)申请大小的不同。栈获得的空间较小,而堆获得的空间较大;
(3)申请效率的不同。栈由系统自动分配,速度较快,而堆一般速度比较慢;
(4)存储内容的不同。栈在函数调用时,函数调用语句的下一条可执行语句的地址第一个进栈,然后函数的各个参数进栈,其中静态变量是不入栈的。而堆一般是在头部用一个字节存放堆的大小,堆中的具体内容是人为安排;
(5)底层不同。栈是连续的空间,而堆是不连续的空间。
(6)生长方向不同。堆的生长方向向上,内存地址由低到高;栈的生长方向向下,内存地址由高到低。
(7)管理方式不同。栈由操作系统自动分配释放,无需我们手动控制;堆的申请和释放工作由程序员控制,容易产生内存泄漏;
52、ES5 和 ES6 分别有几种方式声明变量
ES5 有两种:var 和 function
ES6 有六种:增加四种,let、const、class 和 import
注意:let、const、class声明的全局变量再也不会和全局对象的属性挂钩。
1、var
没有块的概念,可以跨块访问,不能跨函数访问;
存在变量提升
2、let
let声明的的变量只在它所在的代码块有效;
不存在变量提升。let不会像var那样发生“变量提升”,因此,变量需要先声明后使用,否则报错
不允许重复声明
3、const
一旦声明就必须立即初始化;
一旦声明,常量值就不能改变(指堆内存中的地址不能改变)
其他和let一样
4、function()
函数声明后不会立即执行,需要调用的时候才会执行;
对支持es5和es6浏览器环境在块作用域内有一定区别,所以应该避免在块作用域内声明函数。
5、class
相比于对象原型的方式更清晰
更像面向对象编程的语法
6、import
import命令接收一对大括号,其里面的变量名必须与被导入模块对外接口的名称相同
用as关键字可以将输入的变量名重命名
import命令输入的变量都是只读的
import命令具有提升效果,会提升到整个模块的头部,首先执行(因为Import命令是在编译阶段执行的,在代码运行之前)
import是静态执行,不能使用表达式和变量
import会执行所加载的模块
52、谈谈你对ES6的理解
(1)新增模板字符串(为JayaScript提供了简单的字符串插值功能)
(2)箭头函数
(3)for...of (用来遍历数据一例如数组中的值 。)
(4)arguments 对象可被不定参数和默认参数完美代替。
(5)ES6将promise对象纳入规范,提供了原生的Promise对象。
(6)增加了let和const命令,用来声明变量。
(7)增加了块级 作用域。
(8)let命令实际上就增加了块级作用域。
(9)引入module模块的概念
53、forEach、for...in 、for...of三者的区别
(1)forEach遍历数组,但不能使用break、continue和return语句
(2)for…in是用来循环带有字符串key的对象的方法。实际是为循环”enumerable“(可枚举)对象而设计的。Js基本数据类型自带的原型属性不可枚举,通过Object.defineProperty0方法指定enumeralbe为false的属性不可枚举。
(3)for...in循环出的是key,for…of循环出的是value。
(4)for…of数组对象都可以遍历,它是ES6中新增加的语法。一个数据结构只有部署了 Symbol.iterator 属性, 才具有 iterator接口可以使用 for…of循环。for…of遍历对象需要通过和Object.keys()
哪些数据结构部署了 Symbol.iteratoer属性了呢?完美体育
数组 Array
Map
Set
String
arguments对象
Nodelist对象, 就是获取的dom列表集合
54、什么是事件流?什么是事件冒泡?什么是事件捕获?
事件流:从页面中接收事件的顺序。也就是说当一个事件产生时,这个事件的传播过程,就是事件流。
冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。
捕获型事件:事件从最不精确的对象(document 对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定)。
在添加事件时用addEventListener(event,fn,useCapture)方法,基中第3个参数useCapture是一个Boolean值,用来设置事件是在事件捕获时执行,还是事件冒泡时执行。
注意:IE浏览器用attachEvent()方法,此方法没有相关设置,不过IE的事件模型默认是在事件冒泡时执行的,也就是在useCapture等于false的时候执行,所以把在处理事件时把useCapture设置为false是比较安全,也实现兼容浏览器的效果。
如何阻止事件冒泡?
w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true,return false也能阻止冒泡
如何阻止默认事件?
w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false,return false也能阻止默认行为
55、响应事件有哪些?
(1)鼠标单击事件( onclick )
(2)鼠标经过事件( onmouseover )
(3)鼠标移开事件( onmouseout )
(4)光标聚焦事件( onfocus )
(5)失焦事件( onblur )
(6)内容选中事件( onselect )
(7)文本框内容改变事件( onchange )
(8)加载事件( onload )
(9)卸载事件( onunload )