面试题

时间:2021-6-9 作者:qvyue

一、js的数据类型

值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol,大数值类型(BigInt)

引用数据类型:对象(Object)、数组(Array)、函数(Function)、日期(Date)。

注:Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值(标识符)。

二、什么是函数

JS函数的概念

函数就是把特定功能的代码抽取出来,使之成为程序中的一个独立实体。

  1. 函数的作用

正如函数的概念, 我们可以根据需要, 将特定的功能用函数来包裹(封装)

  1. 使用函数的好处

1, 函数可以在同一个程序或其他程序中多次重复使用(通过函数名调用) 2, 使程序变得更简短而清晰 , 提高可读性 3, 有利于程序维护

三、本地对象、内置对象和宿主对象

1.内部对象

js中的内部对象包括Array、Boolean、Date、Function、Global、Math、Number、Object、>RegExp、String以及各种错误类对象,包括Error、EvalError、RangeError、ReferenceError、>SyntaxError和TypeError。

其中Global和Math这两个对象又被称为“内置对象”,这两个对象在脚本程序初始化时被创建,不必实例化这两个对象。

2.宿主对象

宿主对象就是执行JS脚本的环境提供的对象。对于嵌入到网页中的JS来说,其宿主对象就是浏览器 提供的对象,所以又称为浏览器对象,如IE、Firefox等浏览器提供的对象。不同的浏览器提供的 宿主对象可能不同,即使提供的对象相同,其实现方式也大相径庭!这会带来浏览器兼容问题, 增加开发难度。浏览器对象有很多,如Window和Document等等。

3.自定义对象

顾名思义,就是开发人员自己定义的对象。JS允许使用自定义对象,使JS应用及功能得到扩充

四、数组(Array)

1.基本方法

push() 从后面添加元素,返回值为添加完后的数组的长度
pop() 从后面删除元素,只能是一个,返回值是删除的元素
shift() 从前面删除元素,只能删除一个 返回值是删除的元素
unshift() 从前面添加元素, 返回值是添加完后的数组的长度
splice(i,n) 删除从i(索引值)开始之后的那个元素。返回值是删除的元素
concat() 连接两个数组 返回值为连接后的新数组
split() 将字符串转化为数组
sort() 将数组进行排序,默认根据ASCII码比较,返回值是排好的数组
reverse() 将数组反转,返回值是反转后的数组
slice(start,end) 切去索引值start到索引值end的数组,不包含end索引的值,返回值是切出来的数组
indexOf() 查找某个元素的索引值,若有重复的,则返回第一个查到的索引值若不存在,则返回 -1

2.高阶函数(1)

forEach(callback) 遍历数组,无return 即使有return,也不会返回任何值,并且会影响原来的数组
map(callback) 映射数组(遍历数组),有return 返回一个新数组 。

注意:forEach()和map()的区别

  1. arr.forEach()是和for循环一样,是代替for。arr.map()是修改数组其中的数据,并返回新的数据。
  1. arr.forEach() 没有return arr.map() 有return

3.高阶函数(2)

filter(callback) 过滤数组,返回一个满足要求的数组
every(callback) 依据判断条件,数组的元素是否全满足,若满足则返回ture
some() 依据判断条件,数组的元素是否有一个满足,若有一个满足则返回ture
reduce(callback, initialValue) 迭代数组的所有项,累加器,数组中的每个值(从左到右)合并,最终计算为一个值
lastIndexOf() 和arr.indexOf()的功能一样,不同的是从后往前查找
Array.from() 将伪数组变成数组,就是只要有length的就可以转成数组。 —es6
Array.of() 将一组值转换成数组,类似于声明数组 —es6
find(callback) 找到第一个符合条件的数组成员
findIndex(callback) 找到第一个符合条件的数组成员的索引值
fill(target, start, end) 使用给定的值,填充一个数组
includes() 判断数中是否包含给定的值
keys() 遍历数组的键名
values() 遍历数组键值
entries() 遍历数组的键名和键值

五、字符串(String)

字符串的恒定性

字符串的方法修改字符,不会改变原来的字符串,叫做恒定性

字符串的方法

charAt(): 返回指定下标位置的字符。如果index不在0-str.length(不包含str.length)之间,返回空字符串。
charCodeAt(): 返回指定下标位置的字符的unicode编码,这个返回值是 0 – 65535 之间的整数。
indexOf(): 返回某个指定的子字符串在字符串中第一次出现的位置
toLowerCase()把字符串转为小写,返回新的字符串。
toUpperCase(): 把字符串转为大写,返回新的字符串。
lastIndexOf(): 返回某个指定的子字符串在字符串中最后出现的位置。
slice(): 返回字符串中提取的子字符串。
substring(): 提取字符串中介于两个指定下标之间的字符。
split(): 把字符串分割成字符串数组。
substr(): 返回从指定下标开始指定长度的的子字符串
replace(): 在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
match(): 返回所有查找的关键字内容的数组。

六、浏览器渲染页面的原理及流程

浏览器将域名通过网络通信从服务器拿到html文件后,如何渲染页面呢?

1.根据html文件构建DOM树和CSSOM树。构建DOM树期间,如果遇到JS,阻塞DOM树及CSSOM树的构建,优先加载JS文件,加载完毕,再继续构建DOM树及CSSOM树。 2.构建渲染树(Render Tree)。 3.页面的重绘(repaint)与重排(reflow,也有称回流)。页面渲染完成后,若JS操作了DOM节点,根据JS对DOM操作动作的大小,浏览器对页面进行重绘或是回流

面试题
image

七、重绘和回流(repaint&reflow)

当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流

导致回流的操作:

1、页面首次渲染
2、浏览器窗口大小发生改变
3、元素尺寸或位置发生改变
4、元素内容变化(文字数量或图片大小改变而引起的计算值宽度和高度改变)
5、元素字体大小变化
6、添加或者删除可见的DOM元素
7、激活CSS伪类(例如::hover)
8、查询某些属性或调用某些方法
9、offsetWidth,width,clientWidth,scrollTop/scrollHeight的计算,会使浏览器将渐进回流队列Flush,立即执行回流。

当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘

回流必定会发生重绘,重绘不一定会引发回流。

八、如何避免重绘和回流?

css:
1.避免使用table布局,可能很小的一个小改动会造成整个table的重新布局
2.尽可能在DOM树的最末端改变class。
3.避免设置多层内联样式。
4.将动画效果应用到position属性为absolute或fixed的元素上。
5.动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用requestAnimationFrame
6.避免使用CSS表达式(例如:calc())
7.使用transform替代top
8.使用visibility替换display: none,因为前者只会引起重绘,后者会引发回流(改变了布局)
将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点

js:
1.避免频繁操作样式,最好一次性重写style属性,cssText,或者将样式列表定义为class并一次性更改class属性。
2.避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
3.也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
4.避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
5.对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。

九、什么是闭包(Closure)

闭包是这样一种机制:

函数嵌套函数,内部函数可以引用外部函数的参数和变量,参数和变量不会被垃圾回收机制所收回.

闭包的好处:

  1. 可以让一个变量长期驻扎在内存当中不被释放
  1. 避免全局变量的污染, 和全局变量不同, 闭包中的变量无法被外部使用
  1. 私有成员的存在, 无法被外部调用, 只可以自己内部使用

闭包的用途

1.实现缓存

2.存储值与避免变量全局污染

使用闭包的注意点

(1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。 (2)闭包会在父函数外部,改变父函数内部变量的值。

十、垃圾回收机制(GC)

JS引擎会在一定的时间间隔来自动对内存进行回收(把内存释放)

JS垃圾回收机制有两种: 1, 标记清除, 2, 引用计数

1, 标记清除: js会对变量做一个标记Yes or No的标签以供js引擎来处理, 当变量在某个环境下被使用则标记为yes, 当超出该环境(可以理解为超出作用域)则标记为no, js引擎会在一定时间间隔来进行扫描, 会对有no标签的变量进行释放(将该变量所占的内存释放掉)

2, 引用计数: 对于js中引用类型的变量, 采用引用计数的内存回收机制, 当一个引用类型的变量赋值给另一个变量时, 引用计数会+1, 而当其中有一个变量不再等于值时, 引用计数会-1, 如果引用计数为0, 则js引擎会将其释放掉

十一、什么是回调函数(callback)

回调函数也是一种高阶函数,把一个函数当做另外一个函数的参数,在另外一个函数内部被执行和传递参数

好处:

1.解决异步 2.对函数进行功能扩展

缺点:

1.容易造成回调地狱,回调地狱不方便维护与理解, 2.解决方案使用 promise + async + await

十二、什么是ajax

AJAX (阿贾克斯 Asynchronous Javascript And Xml ) 异步JavaScript和XML,是指一种创建交互式网页应用的网页开发技术, 可以访问服务器数据的局部刷新的技术

核心对象: XMLHttpRequest

ajax的异步如何获取到数据?

使用onreadystatechange事件(事件队列event loop的宏任务),并结合callback回调函数

ajax的同步,发送请求时会占据 (thread main)主线程,造成阻塞,不推荐使用

十三、get请求与post请求的区别?

GET在浏览器回退时是无害的,而POST会再次提交请求。 GET请求会被浏览器主动cache,而POST不会,除非手动设置。 GET请求只能进行url编码,而POST支持多种编码(文字,图片,电影..)方式。 GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。 GET请求在URL中传送的参数是有长度限制的,而POST么有。 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。 GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。 GET参数通过URL传递,POST放在Request body中。 GET产生的URL地址可以被Bookmark,而POST不可以。

注意:GET产生一个TCP数据包;POST产生两个TCP数据包。Firefox就只发送一次

十四、HTTP协议

1.什么是http协议

超文本传输协议HyperText Transfer Protocol
它是基于TCP协议的应用层传输协议,
简单来说就是客户端和服务端进行数据传输的一种规则

2.http 协议一共有五大特点:

HTTP 是一个属于应用层的面向对象的协议有五大特点

1.支持客户/服务器模式。 2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种 方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。 3.灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type(Content-Type是HTTP包中用来表示内容类型的标识)加以标记。 4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开式连接。采用这种方式可以节省传输时间。 5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

3.请求报文(request)

1.请求行 [请求方式 url地址 协议(1.0/1.1/2.0) ]
2.请求头部 [content-type,cookie]
3.请求体 [数据]

面试题
image
面试题
image

4.响应报文 (response)

1.状态行 [协议, 状态码,短语]
2.响应头 [content-Type,…]
3.响应体 [数据]

面试题
image
面试题
image

十五、Promise

回调函数是用来解决异步或对函数进行功能扩展,如果滥用回调函数的嵌套,就会形参回调地狱 回调地狱,不方便维护与代码的理解,就可以采用Promise. promsie是一个类,需要被实例化

promsie 有三种状态
1.pending 等待 默认是 等待
2.fulfilled 完成
3.rejected 拒绝
它们是不可以逆

promsie的原型方法

then() 里面有2个函数,第1个函数取resolve的结果,第2个参数取reject的结果 catch() 捕获 reject的结果 finally() 只要执行resolve或reject后,都会执行finally

promise的静态方法

Promise.all() ,all方法里需要填入一个数组,数组里必须都是支持promise的方法,所有的结果

Promise.race(),race方法里需要填入一个数组,谁先执行,就只取谁的结果

Promise.resolve() 只执成功,并返回一个新的promise对象

Promise.reject() 只执失败,并返回一个新的promise对象

ES7 async await

await关键字后面必须接promise对象,有await关键字的地方,必须是一个async 异步函数

它能解决,把异步像同步一样的被调用

十六、同源策略

同源策略是一种ajax的安全机制,

如果出现 协议,域名,端口,三者不统一,就会产生跨域
https://www.baidu.com
http://www.baidu.com //协议不同,跨域

http://www.baidu.com
http://mail.baidu.com 二级域名
http://aaa.bbb.baidu.com 三级域名 域名不同,跨域

http://www.baidu.com:8080
http://www.baidu.com:5500 端口不一致,跨域

如何解决跨域(CORS)呢?

目前常见的方案,

  1. 在后端的响应头加上一句 Access-Control-Allow-Origin:*,这里的*表示所有请求,都可以访问该服务

  2. 采用非官方的跨域方案 ,JSONP, 它算不上真正ajax请求,它只能算get请求,因为它是利用了带src属性的

    script,不受限制的访问外部资源,再又结合callback回调函数获取数据.

    还要和后端配合使用

  3. 前端使用webpack模块中的server proxy ,实现服务器端代理,来解决跨域

十七、什么是xss攻击?

十八、JSONP和JSON的区别 ?

jsonp 是一种非官方的跨域解决方案,它是利用script的src,不受限制的访问外部资源,并结合callback拿到数据
它并不是真正的ajax,它是一个get请求,更加适合做查询.
json 是一种轻量级的数据结构,能跨平台进行网络传输,能做配置文件.
xml 可扩展性标记语言,是一种重量级的数据格式,也能做跨平台进行网络传输和做配置文件.

十九、什么是oop(面向对象)

oop是一种编程思想,又叫做面向对象编程
它有三大特性
封装 将相同的属性和方法提取成一个类
继承 子类拥有父类的属性和方法
多态
重写 子类重写父类的属性和方法
重载 在同一个类中,同名不同参数 js没有重载
补充: css3大特性
层叠性,继承性,优先级(特殊性)

二十、继承

1. 对象冒充继承 使用 bind,call,apply
缺点:不能继承原型上的属性和方法
2. 原型链继承
缺点:不能让构造函数的属性,初始化
3. 组合继承 (对象冒充+原型继承)
缺点:原型中会有多余的属性,并且是undefined
4. ES6的class和extends继承
5. 寄生组合继承 Object.create(base.prototype);

二十一、递归

1.什么是递归?

函数自己调用自己,要有零界点(结束条件)

2.递归能做什么?

循环的能做的事,递归都能实现

3.递归的使用场景

1. 快速排序使用递归
2. nodejs磁盘文件的遍历,使用递归
3. 管理系统的权限菜单栏(n级菜单栏)
4. 对象的深拷贝

二十二、节流(throttle)与防抖(debounce)

防抖任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行

触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间
// 1、防抖功能函数,接受传参
function debounce(fn,delay==600) {
// 2、创建一个标记用来存放定时器的返回值
let timeout = null;
return function() {
// 3、每次当用户点击/输入的时候,把前一个定时器清除
clearTimeout(timeout);
// 4、然后创建一个新的 setTimeout,
// 这样就能保证点击按钮后的 interval 间隔内
// 如果用户还点击了的话,就不会执行 fn 函数
timeout = setTimeout(() => {
fn.call(this, arguments);
}, delay);
};
}

节流指定时间间隔内只会执行一次任务。

高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率
function throttle(fn,delay=600) {
// 1、通过闭包保存一个标记
let canRun = true;
return function() {
// 2、在函数开头判断标志是否为 true,不为 true 则中断函数
if(!canRun) {
return;
}
// 3、将 canRun 设置为 false,防止执行之前再被执行
canRun = false;
// 4、定时器
setTimeout( () => {
fn.call(this, arguments);
// 5、执行完事件(比如调用完接口)之后,重新将这个标志设置为 true
canRun = true;
}, delay);
};
}

节流和防抖的共同点,都是减少执行频率.

函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,

而函数防抖只是在最后一次事件后才触发一次函数

二十三 defer和async的区别

  • defer:在HTML解析完之后才会执行。如果是多个,则按照加载的顺序依次执行。

  • async:在加载完之后立即执行。如果是多个,执行顺序和加载顺序无关

二十四、前端性能优化

  1. 减少 HTTP 请求数量

    • 基本原理:在浏览器与服务器进行通信时,主要是通过 HTTP 进行通信。浏览器与服务器需要经过三次握手,每次握手需要花费大量时间。而且不同浏览器对资源文件并发请求数量有限(不同浏览器允许并发数),一旦 HTTP 请求数量达到一定数量,资源请求就存在等待状态,这是很致命的,因此减少 HTTP 的请求数量可以很大程度上对网站性能进行优化。

      1. CSS Sprites:国内俗称 CSS 精灵,这是将多张图片合并成一张图片达到减少 HTTP 请求的一种解决方案,可以通过 CSS background 属性来访问图片内容。这种方案同时还可以减少图片总字节数,节省命名词汇量(由命名多张图片文件变成一张,哈哈哈)。

      2. 合并 CSS 和 JS 文件:现在前端有很多工程化打包工具,如:grunt、gulp、webpack等。为了减少 HTTP 请求数量,可以通过这些工具再发布前将多个 CSS 或者 多个 JS 合并成一个文件。

      3. 采用 lazyLoad:俗称懒加载,可以控制网页上的内容在一开始无需加载,不需要发请求,等到用户操作真正需要的时候立即加载出内容。这样就控制了网页资源一次性请求数量。

  2. 控制资源文件加载优先级

    • 基本原理:说到这里就需要知道浏览器加载 HTML 内容的原理,浏览器在加载 HTML 内容时,是将 HTML 内容从上至下依次解析,解析到 link 或者 script 标签就会加载 href 或者 src 对应链接内容,为了第一时间展示页面给用户,就需要将 CSS 提前加载,不要受 JS 加载影响。

      1. 遵循原则:主要文件放在 head 内部,次要文件放在 body 底部。一般情况下都是 CSS 在头部,JS 在底部。
  3. 利用浏览器缓存

    • 基本原理:浏览器缓存分强缓存和协商缓存,他们是将网络资源存储在本地,等待下次请求该资源时,如果命中就不需要到服务器重新请求该资源,直接在本地读取该资源。

      1. 强缓存:在 web 服务器返回的响应中添加 Expires 和 Cache-Control Header。

      2. 协商缓存:通过【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】这两对 Header 分别管理。

  4. 使用 CDN

    • 基本原理:CDN的全称是Content Delivery Network,即内容分发网络。
  5. 减少重排(Reflow)

    • 基本原理:重排是 DOM 的变化影响到了元素的几何属性(宽和高),浏览器会重新计算元素的几何属性,会使渲染树中受到影响的部分失效,浏览器会验证 DOM 树上的所有其它结点的 visibility 属性,这也是 Reflow 低效的原因。如果 Reflow 的过于频繁,CPU 使用率就会急剧上升。

      1. 减少 Reflow,如果需要在 DOM 操作时添加样式,尽量使用 增加 class 属性,而不是通过 style 操作样式。
  6. 减少 DOM 操作
    使用createDocumentFragment

  7. 图标使用 IconFont 替换

https://www.jianshu.com/p/d9c20eafa67e 网页性能优化

https://segmentfault.com/a/1190000017329980 你真的了解回流和重绘吗

二十五.Promise 的 then 为什么是异步的?(从微任务和宏任务解释)

Promise是宏任务(同步执行),但Promise 的回调函数属于异步任务,会在同步任务之后执行(比如说 then、 catch 、finally)。

Promise 的回调函数不是正常的异步任务,而是微任务(microtask)。它们的区别在于,正常任务追加到下一轮事件循环,微任务追加到本轮事件循环。这意味着,微任务的执行时间一定早于正常任务。

二十六. new的在实例化的时候做了那些事情

1.在函数内,隐式的创建一个空对象
2.将空对象的指针指向该构造函数的原型
3.将this指向obj空对象,再往obj空对象上添加属性和方法
4.隐士return this;

二十七.如何自己实现一个new

function funcNew(obj,...args){
    //创建一个新的对象 它的原型就是传入对象的原型
    const newObj=Object.create(obj.prototype);
    //改变传入对象的this指向 指向新对象 并添加属性和方法
    const result=obj.apply(newObj,args);
    //当result等于对象并内容不为空时 return结果 否则返回新的对象=传入的对象
    return (typeof result==='object' && result !==null)?return : newobj;
}

二十八.事件委托

  • 什么是事件委托: 将子元素的事件委托给父元素
    • 原理:利用事件冒泡
  • 事件委托的好处:减少 DOM 操作,从而减少浏览器的重绘与重排次数,提升性能。

二十九. methods、watch、computed的区别

  • methods 普通业务处理
适合用于业务逻辑处理,数据不能够缓存,每次使用都会重新调用  
  • watch 单个数据、路由
适合监听单个数据的变化 ,也可以监听路由的变化   
  • computed 属性计算
适合计算属性 ,可以缓存数据    

this指向

面试题
this指向-new.png

lazyload 原理

面试题
赖加载,节流-防抖.png

v-model 双向绑定原理

 var obj = {};
  //proxy
  Object.defineProperty(obj, 'a', {
    get() {
      return this;
    },
    set(val) {
      document.getElementById('box').innerHTML = val;
      document.getElementById("txt").value = val;
    }
  })
  obj.a = 1;
  document.getElementById('txt').addEventListener('keyup', e => {
    obj.a = e.target.value
  })

其他补充

面试题
6ICTL`8DD`GEK_9Z(I89X0Z.png

webpack 和gulp 的区别

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。