HTML面试

一、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()是修改数组其中的数据,并返回新的数据。
  2. 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操作动作的大小,浏览器对页面进行重绘或是回流

七、重绘和回流(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. 可以让一个变量长期驻扎在内存当中不被释放
  2. 避免全局变量的污染, 和全局变量不同, 闭包中的变量无法被外部使用

闭包的用途

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.请求体    [数据]

请求报文格式

请求报文

4.响应报文 (response)

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

响应报文

响应报文

十五、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 ,实现服务器端代理,来解决跨域

posted on 2022-01-04 08:50  文加宁  阅读(27)  评论(0编辑  收藏  举报