首页IT科技技术面试八股文(前端常见面试八股文)

技术面试八股文(前端常见面试八股文)

时间2025-09-15 12:01:13分类IT科技浏览5082
导读:HTML篇 1、H5新增标签有哪些? 一、语义化标签...

HTML篇

1                 、H5新增标签有哪些?

一                        、语义化标签

header        、footer                 、nav                        、aside        、section         、article

语义化的意义?

1                        、更适合搜索引擎的爬虫爬取有效的信息                 ,利于SEO                 。

2                、对开发团队很友好                        ,增加了标签的可读性        ,结构更加的清晰                 ,便于团队的开发和维护                        。

二         、多媒体标签

视频标签:video

属性:src                         、 Poster(加载等待画面的图片)                、muted(静音)

音频标签: audio

属性:src、loop                         、controls(调出当前控件)

三                        、表单元素、控件

输入框input中新增 type                        ,类型可为                 、email                        、url        、data                 、number等

required                        、placeholder

2        、src和href的区别

src和href都是对外部资源的引用        ,区别如下:

src: 表示对资源的引用         ,用在js脚本         、img                        、frame等元素上                        ,当浏览器解析到该元素时                ,会暂停其他资源的下载和处理         ,直到该资源加载                、编译         、执行完成                         ,所以js脚本会放在页面的底部                ,而不是头部        。

href:表示超文本引用,指向一些网络资源                         ,当浏览器识别它指向的文件时                        ,就会并行下载资源,不会停止对当前文件的处理                 ,用在a                         、link上

3                、defer和async

参考博文:

https://blog.csdn.net/weixin_42561383/article/details/86564715

默认情况下                        ,浏览器是同步加载js脚本的        ,即渲染引擎遇到 script标签就会停下来                 ,等执行完脚本                        ,再去继续向下渲染        ,如果是外部脚本         ,还必须加入脚本的下载时间                 。

加入脚本的很多而且体积很大的话                        ,下载执行 就会占用很大的时间                ,照成浏览器堵塞         ,用户就会感觉卡死了                         ,没有任何响应                ,体验极差,所以浏览器允许脚本的异步加载                         ,方式如下:

<script src="path/to/myModule.js" defer></script> <script src="path/to/myModule.js" async></script>

关键字就是defer和async                        ,脚本会异步加载                        。渲染引擎遇到这行命令就会开始下载外部的脚本,但是并不会等待其脚本下载完成和执行完成                 ,而是直接执行后面的命令        。

defer和async的区别:

defer:需要等待整个页面正常DOM渲染完成后                        ,才会执行下载好的js脚本        ,并且是按下载完后的顺序执行         。

async:当外部的js脚本下载完成后                 ,渲染引擎会暂停DOM渲染                        ,开始执行下载好的JS脚本的内容        ,在执行完成后         ,再去渲染                        。

简单的说:

defer是需要等DOM元素都渲染完成后                        ,才去执行下载完成的js脚本

async是当js脚本下载完成后                ,开始执行的时候中断DOM渲染         ,执行js脚本的内容                         ,执行完成再去渲染DOM元素

没有defer或async属性                ,浏览器会立即下载并执行相应的脚本,并且在下载和执行时页面的处理会停止                。可能形成页面堵塞

不用异步加载的话可以把外部引入的脚本放在</body>前即可

4、行内元素与块级元素

块级元素: 独占一行                         ,可以设置宽高                        ,设置margin和padding都有效,代表如下:

div                         、p                        、h1…h6、table                 、tr                        、ol        、li                 、ul

行内元素元素: 可以排成一行                 ,设置宽高无效                        ,对margin设置左右方向有效        ,而上下无效                 ,padding设置都无效                        ,代表如下:

基本上都是文本标签

span                        、img        、b         、strong                        、font                、br         、a

5                         、title与h1                、b与strong、i与em的区别

Strong表示的是重点内容        ,有语气加强的含义         ,                        ,会重读                ,而展示强调的内容

b只是展示强调的内容

title属性没有明确意义只表示是个标题         ,H1则表示层次明确的标题                         ,对页面信息的抓取也有很大的影响

i内容展示为斜体                ,em表示强调的文本

6                         、回流(重拍)与重绘

先了解下HTML文文件渲染的过程

都发生在渲染DOM树(Render Tree)后的过程中,其中Layout是回流                         ,Painting是重绘

回流:浏览器中进行布局的过程就是回流

重绘:浏览器进行 渲染就是重绘

触发回流的一些条件:

1                        、添加或者删除可见的DOM元素;

2、元素位置改变;

3                 、元素尺寸改变——边距                        、填充        、边框                 、宽度和高度

4                        、内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变;

5        、页面渲染初始化;

6         、浏览器窗口尺寸改变——resize事件发生时;

触发重绘的一些条件:

1                        、改变背景色

2                、改变透明度

简单的说                        ,就是不影响布局的情况下,改变的就是重绘

性能优化方法:

减少浏览器的回流行为达到性能优化         。

1         、用transform代替位移

2                         、用visibility:hidden透明度代替display:none

3                、使用display:none技术                 ,只引发两次回流和重绘;

4、使用cloneNode(true or false)和replaceChild技术                        ,引发一次回流和重绘;

5                         、让元素脱离动画流        ,减少回流的Render tree的规模;

7                        、cookie、localStorage 和 sessionStorage的区别及应用实例

详解cookie

简单的理解是因为http协议的无状态性                 ,所以需要cookie去把特别的信息保存下来                        ,当然保存的是在浏览器中        ,下面简单的讲解下逻辑

1                 、浏览器向服务器发送请求         ,传输一些信息

2                        、服务器收到请求                        ,在响应体中通过set-cookie返回字段                ,保存在浏览器中                         。

3        、浏览器再次发送请求时会携带cookie         ,根据服务器中对比                         ,做一个判断                。

在前端的js代码中通过:

document.cookie = ‘name=value’

去设置cookie                ,其中cookie带有如下属性

max-age/expires:可设置cookie的有效时间,其中expires必须时GMT的时间格式,可用new Date().toGMTString()去对时间进行转换。在没有设置时间时                         ,cookie会随着浏览器的关闭                        ,而被删除

domain:可设置访问该cookie的域名

path:可设置访问此cookie的页面路径

Size:设置cookie的大小

http:cookie的httponly属性,如果为true                         。则只有在http请求头中会有此cookie的信息                 ,而不能通过document.cookie来进行访问

删除cookie

只需要把cookie的有效时间设置为当前日期的前任何时间即可

下面是列子:

<body> <form> 用户名<input type="text" name="username1111" /> 密码<input type="password" name="pwd" id="pwd" /> 提交<input id="submit" type="submit" /> 记住密码<input type="checkbox" /> <button onclick="hand1()" id="delete">删除cookie</button> </form> <script> let lineTime = new Date("2022-7-20 19:7:30").toGMTString(); console.log("lineTime: ", lineTime); let submit = document.getElementById("submit"); let username = document.querySelector(input[type="text"]); let pwd = document.querySelector(input[type="password"]); let check = document.querySelector(input[type="checkbox"]); let arr = document.cookie.split(";"); console.log(arr); let arr1 = []; arr.forEach((item) => { arr1.push(item.split("=")); }); let cookie = {}; for (let i = 0; i < arr1.length; i++) { let name = arr1[i][0]; let value = arr1[i][1]; cookie[name] = value; } if (document.cookie) { username.value = cookie.yourname; check.checked = true; } submit.addEventListener("click", (e) => { let value = username.value; let key = "yourname"; if (check.checked && username.value !== "") { document.cookie = `${key}=${value};expires=${lineTime}`; e.preventDefault(); } }); function hand1() { let key = "yourname"; document.cookie = `${key}=; expires=Thu, 01 Jan 1970 00:00:00 GMT`; console.log(document.cookie); e.preventDefault(); } </script> localStorage 和sessionStorage

前面得cookie作为一个存储手段进行举例                        ,但是在H5中新增了两种存储方式        ,其中使用方法如下:

localStorage.key() :拿到指定key得值

localStorage.setItem(名,值):设置相关的储存值

localStorage.getItem(名):取出对应名的值

localStorage.removeItem(名):移除掉相关的值

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <input type="text" /> <button onclick="hand1()" class="hand">搜索</button> <ul id="one"></ul> <script> if (sessionStorage.length > 0) { for (let i = 0; i < sessionStorage.length; i++) { let key = sessionStorage.key(i); let newLi = document.createElement("li"); newLi.innerHTML = `${sessionStorage.getItem(key)}`; let ul = document.getElementById("one"); ul.append(newLi); let close = document.createElement("span"); close.innerHTML = `删除`; newLi.appendChild(close); close.addEventListener("click", (e) => { sessionStorage.removeItem(key); newLi.parentNode.removeChild(newLi); }); } } let search = document.querySelector(input[type="text"]); let hand = document.getElementsByClassName("hand")[0]; let temp = 0; function hand1() { if (search.value) { console.log(111); temp++; sessionStorage.setItem(`${temp}`, search.value); let newLi = document.createElement("li"); newLi.innerHTML = `${sessionStorage.getItem(temp)}`; let ul = document.getElementById("one"); ul.append(newLi); let close = document.createElement("span"); close.innerHTML = `删除`; newLi.appendChild(close); close.addEventListener("click", (e) => { console.log(temp); sessionStorage.removeItem(temp); newLi.parentNode.removeChild(newLi); }); } } </script> </body> </html>

sessionStorage使用的方法和localStorage一致                        。

三者的区别

cookie具有时效性                 ,可以手动的去设置需要保存的时间                        ,内存大小大概为4KB        ,内容保存在客户端上         ,删除的话把过期时间设置为前一天即可。

localStorage                        ,除非手动去删除                ,不然一直会保存         ,内存大小为5MB

sessionStorage                         ,临时会话保存                ,相关页面关闭掉就自动删除,内容大小为5MB

建议理解三者的基本使用再去理解这面试题                         ,因为工作中也能用到

8                 、同源策略与跨域问题

什么是同源策略

借用阮一峰老师的描述:

简单地说就是为了网页之间的安全性                        ,但是在平常的工作中,我们会遇到别的资源请求问题                 ,也就是跨域问                        ,下面给出几种常见的跨域解决问题的方案

跨域解决方案

参考B站技术蛋老师的讲解

1                        、JSONP

json with padding        ,也就是JSON的填充方法                 。在服务器与客户端之间的格式我们常用的是JSON格式                        。

我们用script标签获取数据                 ,其中的数据会被执行                        ,所以我们一般会给数据外包一个js函数        ,然后再外包一层作为传输用的json格式        。

我们知道通过script标签请求的资源中         ,并不会受到同源策略的限制                        ,而jsonp方法就是通过这个方式去实现别的资源共享                ,简单原理如下:

原理可分为 客户端与服务器

客户端:客户端上去写一个函数         ,专门用来处理跨域获取服务器JSON数据的方法                         ,在传入的url上写额外的参数                ,传到服务器,同时客户端收到服务器传过来的数据后                         ,调用提前设定好的函数                        ,执行服务器传过来的数据                 。

服务器:数据源是在服务器上存在的,而我们需要再然后服务器对额外的参数进行判断                 ,把数据外包一个js函数                        ,通过JSON的方式传给客户端                        。

2        、CORS

当浏览器向服务器发起请求的时候        ,会在请求头中添加origin(协议+主机+端口)                 ,也就是表明自己的协议+主机+端口                        ,当服务器接收到这个origin的时候        ,就得添加头部Access-Control-Allow-Origin到响应里面         ,浏览器看到服务器传回来的Access-Control-Allow-Origin                        ,就可以进行判断是否进行跨域请求

核心其实就是设置Access-Control-Allow-Origin

9         、检测数据类型的方法

1                        、typeof

typeof在检测null                、object         、array                         、data的结果中都是object                ,所以无法用来区分这几个类型的区别

<script> let a = [ "123", 123, false, true, Symbol(1), new Date(), null, undefined, function () {}, {}, [] ]; a.forEach((item) => { console.log(item, "检测出的值:", typeof item); }); </script> 2                、instanceof

缺点是只能检测该对象是否存在目标对象的原型上

[对象] instanceof [构造函数]

<script> function Foo() {} var f1 = new Foo(); var d = new Number(1); console.log(f1 instanceof Foo); // true console.log(d instanceof Number); //true console.log(123 instanceof Number); //false -->不能判断字面量的基本数据类型 </script> console.log(Number instanceof Number) // false console.log(String instanceof String) // false console.log(Fun instanceof Fun) // false         ,这里Fun指的是函数 console.log(null instanceof Object) // false                         ,null不具有任何对象的特性,也没有__proto__属性

instanceof 用于判断对象类型                ,但以上情况的结果都为false,请注意        。

instanceof 的原理

因为会一直往原型链上查找

L代表instanceof左边                         ,R代表右边

function hand(L, R) { let L = L._propto_; while (true) { if (L === null) { return false; } if (L === R.propotype) { return true; } L = L._propto_; } } 3、constructor

constructor 不能判断null                         、undefind                        ,因为他们不是构造对象

<script> let a = [ "123", 123, false, true, Symbol(1), new Date(), function () {}, {}, [], null, undefined, ]; try { a.forEach((item) => { console.log(item, "检测出的值:", item.constructor.name); }); } catch (e) { console.log(e); } </script> 4                        、Object.prototype.toString.call

可以检测出所有的数据类型

<script> let a = [ "123", 123, false, true, Symbol(1), new Date(), function () {}, {}, [], null, undefined, ]; try { a.forEach((item) => { console.log( item, "检测出的值:", Object.prototype.toString.call(item) ); }); } catch (e) { console.log(e); } </script>

在使用Array.prototype.toString.call的时候,遇到null、undefined会出现报错

10                 、阻止默认事件

在面试中我们会被问到事件冒泡                        、默认事件等概念                 ,下面做一些简单的了解:

事件冒泡

1.原理:元素自身的事件被触发后                        ,如果父元素有相同的事件        ,如click事件                 ,那么元素本身的触发状态就会传递                        ,也就是冒到父元素        ,父元素的相同事件也会一级一级根据嵌套关系向外触发         ,直到document/window                        ,冒泡过程结束         。

2.使用范围:冒泡事件只是针对于click相关的事件                ,还有click的分支事件:mouseup        、mousedown

默认事件:

比如点击a标签会默认打开                 、input提交表单按钮         ,都是默认事件

阻止默认事件但是不阻止事件冒泡

event.preventDefault()

阻止事件冒泡阻止默认事件

event.stopPropagation();

在jquery中阻止事件冒泡和默认行为                         ,在原生js中只阻止事件冒泡

return false

11                        、文档流                ,文本流清除浮动

文档流:

我理解的是页面中的块级元素等DOM元素按照默认的方式去进行排列

文本流:

网页页面上的一些文字的排列

清除浮动的方法及原理:

原理:其实就是让目标元素脱离文档流即可,手段有float:left        、position中的绝对定位和固定定位等

方法:

1         、用伪类去清除浮动

2                        、在浮动元素上添加一个空盒子                         ,写上clear:both的样式

3                、双伪类清除浮动

12         、手写call                         、apply                、bind

1、call

想要手写出就得知道它是怎么使用的                        ,函数.call(绑定this指向,参数一                 ,参数二                        ,…)

<script> function person(a, b, c, d) { console.log(this.name); console.log(a, b, c, d); } let egg = { name: "测试", }; //js创建新函数是在函数原型上去添加 Function.prototype.newCall = function (params) { //先做判断        ,如果绑定的调用的this不是函数                 ,则抛出异常错误 if (typeof this !== "function") { throw new TypeError("不是函数"); } //防止传入null                         、undefinde                        ,和window进行绑定 params = params || window; //先获取传入的参数 let arr = [...arguments].slice(1); //把this指向指向形参的函数,保存this params.fn = this; //带入的参数传入函数中 let result = params.fn(...arr); //删除用完的函数 delete params.fn; return result; }; person.newCall(egg,1,2,3,4) </script> 2                        、apply

apply和call的写法基本一至        ,就是二者接受的参数不同         ,面试apply的写法

函数.apply(this指向对象                        ,[参数1                ,参数2         ,参数3…])

<script> function person(a, b, c, d) { console.log(this.name); console.log(a, b, c, d); } egg = { name: "tom", }; Function.prototype.newApply = function (context) { if (typeof this !== "function") { throw TypeError("不是一个函数"); } context = context || window; context.fn = this; let result if (arguments[1]) { result = context.fn(...arguments[1]); } else { result = context.fn(); } delete context.fn return result }; person.newApply(egg,[1,2,3,4]) </script> 3、bind

bind与前两个的区别如下

1                 、bind返回的是一个函数

2                        、如果是new出来的                         ,返回一个空对象                ,且使创建出来的实例的__proto__指向_this的prototype,且完成函数柯里化

<script> function person(a, b, c, d) { console.log(this.name); console.log(a, b, c, d); } Function.prototype.newBind = function (content) { if (typeof this !== "function") { throw TypeError("不是一个函数"); } let arr = Array.prototype.slice.call(arguments, 1); const that = this; return function fn() { if (this instanceof fn) { return new that(...arr, ...arguments); } else { return that.apply(content, arr.concat(...arguments)); } }; }; egg = { name: "tom", }; person.newBind(egg, 1, 2, 3)(4); </script>

13        、new的过程中发生了什么

其实new的过程中就是this指向改变                 、新创建一个实列的过程                         ,如下

<script> function Mother(tip){ this.tip=tip } let son =new Mother() // 1                        、创建一个son空对象 // 2        、使空对象的隐式原型指向原函数的显示原型 // son_proto_=Mother.prototype // 3         、原函数进行this的绑定                        ,指向空对象 // let result =Mother.call(son,tip) // 4                        、判断函数结果是不是null                、undefined,是就返回之前新对象                 ,不是就返回结果 // return result instanceof Object ? Object: result </script>

14         、js的继承方式

1                         、原型链继承

关键点就是: 继承函数.prototype =new 被继承函数

<script> function person() { this.obj = { age: 10, }; this.speack=function(){ console.log(父元素); } } person.prototype.name = "tom"; //子元素 function son() { this.name = "son1"; } son.prototype = new person(); //原型链继承 let p1 = new son(); console.log(p1.obj.age); //10 console.log(p1 instanceof person); //true console.log(p1.name); //son1 </script>

缺点:

1                、继承单一

2、子类无法向父类的构造函数传参

3                         、所有新实列都会共享父类实列的属性(原型上的属性也是共享的                        ,一个实列修改了原型属性        ,另一个也会被修改)

2                        、原型继承 <script> var person ={ arr: [a,b,c,d] } var p1 =Object.create(person) p1.arr.push(aaa) console.log(p1); //{} console.log(person); </script>

缺点:子类实列共享了父类构造函数的引用属性                 ,不能传参

3、构造函数继承 <script> var person = function (name) { this.name = name; }; person.prototype.age=10 var son = function () { person.call(this, "tom"); }; var p1 =new son() console.log(p1.name);//tom console.log(p1.age);undefined </script>

重点:借用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行)

优点:1                 、可以继承多个构造函数属性

​ 2                        、在子实列中可以向父实列传参

缺点:1        、只能继承父实列的构造函数属性

​ 2                 、每新实列都会有父类构造函数的副本                        ,臃肿

4                        、组合继承 <script> var person = function (name) { this.name = name; }; person.prototype.age=10 var son = function () { person.call(this, "tom"); //构造函数继承 }; son.prototype=new person() //原型链继承 var p1 =new son() console.log(p1.name);//tom console.log(p1.age);undefined </script>

重点:结合了两种模式的优点        ,传参和复用

特点:1        、可以继承父类原型上的属性         ,可以传参                        ,可复用                        。

   2         、每个新实例引入的构造函数属性是私有的                。

缺点:调用了两次父类构造函数(耗内存)                ,子类的构造函数会代替原型上的那个父类构造函数         。 5                        、寄生组合继承 <script> var person = function (name) { this.name = name; }; person.prototype.age = 10; var son = function () { person.call(this, "tom"); //构造函数继承 }; son.prototype = Object.create(person.prototype); //寄生组合继承 son.prototype.constructor = son; var p1 = new son(); console.log(p1.name); //tom console.log(p1.age); //10 </script>

优点

只调用了一次父类构造函数         ,只创建了一份父类属性 子类可以用到父类原型链上的属性和方法 6                、extends继承 <script> class person{ constructor(){ this.name =tom this.speack =()=>{ console.log(我是爹); } } } class son extends person{ constructor(){ super() this.age=12 } } let s1 =new son() console.log(s1.age,s1.name); </script>

ES6出来的

​ 子类只要继承父类                         ,可以不写 constructor                 ,一旦写了,则在 constructor 中的第一句话必须是 super                         。

15         、箭头函数和普通函数的区别

1                         、call                、apply、bind不会改变箭头函数this值                         ,会改变普通函数this值

2                         、箭头函数没有原型属性

3                        、箭头函数不绑定arguments,取而代之用rest参数… 解决

4、箭头函数不能作为构造函数使用                        ,不能使用new

5                 、箭头函数中的 this 和调用时的上下文无关,而是取决于定义时的上下文

16                        、移动端1px像素解决办法

先理解概念                 ,物理像素        、逻辑像素

物理像素:是不同手机型号出厂时携带的像素                        ,也称为硬件像素

逻辑像素:css中记录的像素

问题描述:

在开发的时候ui设计师要求的1px是设备的物理像素        ,而css中的是逻辑像素                 ,它们之间并不是直接等于的关系                        ,存在着比列关系        ,通常可以用 javascript 中的 window.devicePixelRatio 来获取         ,也可以用媒体查询的 -webkit-min-device-pixel-ratio 来获取                。当然                        ,比例多少与设备相关。

解决办法:

1                 、媒体查询利用设备像素比列缩放                ,设置小数像素

css可以这样设置:

.border { border: 1px solid #999 } @media screen and (-webkit-min-device-pixel-ratio: 2) { .border { border: 0.5px solid #999 } } @media screen and (-webkit-min-device-pixel-ratio: 3) { .border { border: 0.333333px solid #999 } }

js可以这样写:

<body><div id="main" style="border: 1px solid #000000;"></div></body> <script type="text/javascript"> if (window.devicePixelRatio && devicePixelRatio >= 2) { var main = document.getElementById(main); main.style.border = .5px solid #000000; } </script>

2                        、媒体查询 + transfrom 对方案1的优化

/* 2倍屏 */ @media only screen and (-webkit-min-device-pixel-ratio: 2.0) { .border-bottom::after { -webkit-transform: scaleY(0.5); transform: scaleY(0.5); } } /* 3倍屏 */ @media only screen and (-webkit-min-device-pixel-ratio: 3.0) { .border-bottom::after { -webkit-transform: scaleY(0.33); transform: scaleY(0.33); } }

17        、伪类与伪元素的区别

首先在知道这个概念之前先了解什么是伪类?伪元素?

1         、伪元素

1                        、伪元素在DOM树中创建了一些抽象元素         ,这些抽象元素并不存在与文档语言中(逻辑上存在                         ,不存在文档树中)

2                、伪元素由两个::开头                ,接的是伪元素得名称(使用两个::是为了区分伪类和伪元素,在CSS2中依然可以用一个:的语法                         ,但是在CSS3中必须使用两个冒号::)

3         、一个选择器只能使用一个伪元素                        ,并且伪元素必须处于选择器语句的最后

伪元素的种类:

2                         、伪类

1                、伪类由一个冒号开头:

2、获取不存在与DOM树中的信息                         。比如<a>标签的:link                         、visited等,这些信息不存在与DOM树结构中                 ,只能通过CSS选择器来获取

伪类的种类:

18                        、移动端、浏览器字体小于12px的解决方案

font-size: 12px;是浏览器字体设置最小的时候                        ,12以下的数值不生效了        ,要是想实现小于12px                 ,方法如下:

transform: scale(0.5);

这时候可能会遇到字体缩放和布局一起缩小了                        ,只需要将字体与容器样式分开写就好了

<style> *, body { padding: 0; margin: 0; } .one { font-size: 20px; transform: scale(0.5); } .father { width: 100px; height: 100ox; background-color: red; } </style> </head> <body> <div class="father"><p class="one">这是一段话</p></div> </body>

19                 、js浮点数精度计算问题解决

一般运算中        ,我们会保留后两位小数         ,这里做点知识扩展

1                        、.toFixed()

语法:

数字.toFixed(2)

括号中的数字是保留的位数                        ,该方法会四舍五入                ,返回的值类型是string型

2        、Math.round()

语法:

Math.round(x)

x是数值

返回值: 给指定的数字值四舍五入到最接近的整数

解决精度运算问题有如下方式:

1                 、 扩大倍数法:有多少位小数就扩大10的n次方

document.write((0.01*100+0.09*100)/100); //输出结果为0.1

2                        、四舍五入法:

document.write((0.01+0.09).toFixed(2)); //保留2位小数,输出结果为0.10 document.write(Math.round((0.01+0.09)*100)/100); //输出结果为0.1

20        、移动端的300毫秒延迟问题

问题描述:

移动端浏览器在派发点击事件的时候         ,通常会出现300ms左右的延迟                        。也就是说                         ,当我们点击页面的时候移动端浏览器并不是立即作出反应                ,而是会等上一小会儿才会出现点击的效果。

方案一:禁用缩放

<meta name="viewport" content="user-scalable=no"> <meta name="viewport" content="initial-scale=1,maximum-scale=1">

方案二:更改默认的视口宽度

<meta name="viewport" content="width=device-width">

方案三:fastclick,解决移动端300ms延迟

FastClick 是 FT Labs 专门为解决移动端浏览器 300 毫秒点击延迟问题所开发的一个轻量级的库                 。FastClick的实现原理是在检测到touchend事件的时候                         ,会通过DOM自定义事件立即出发模拟一个click事件                        ,并把浏览器在300ms之后的click事件阻止掉                        。

直接安装依赖按照官网的教程使用就好了

21         、HTTP缓存

面试中我们常会被到,你知道http缓存的方式有几种吗?这样的问题                 ,下面我简单的介绍下                        ,为什么会有HTTP缓存                        、缓存的方式

1                、存在的意义

我们每一次的网络请求中        ,在请求成功的前提下                 ,服务器都会给我们返回对应的资源                        ,浏览器进行下载        ,但是并不是所以的资源都会被下载         ,比如当某些资源未改变时                        ,浏览器会在本地缓存中拿到它们                ,从而避免了重复下载的过程         ,这也算是一种性能上的优化

可以被缓存的资源:JS文件         、CSS文件                         、图片                、字体包等等

2、缓存的类型

我们可以知道                         ,前端发起HTTP请求的时候                ,会在请求头上携带相关的信息,浏览器就会根据我们携带的信息去判断                         ,本次请求的该资源是否有本地缓存

强缓存

以前的使用中                        ,我们一直用的是expires,也就是当服务器返回响应时                 ,在响应头中将过期的时间写入expires字段中                        ,自己随便找个网站F12打开调试台        ,找一条网络请求即可

可以看到expires中写入了过期的时间范围                 ,那整个流程是怎么样的呢?

当首次资源发送时:

再次发送资源时                        ,浏览器会把expires中的时间戳和本地时间去进行对比        ,如果本地时间小于expires中的时间         ,则在缓存中拿到这个资源                        ,这里的时间戳由于是服务器上传的                ,所以需要保证浏览器和服务器上的时间一致

expires是通过拿到时间戳去进行比对的         ,在后面又增加了Cache-Control 中的max-age 字段也允许我们通过设定时间长度来达到同样的目的        。

max-age可以看作是对expires的补充                         ,在日常工作中                ,我们可能用max-age较多,但是如果要实现向下兼容                         ,expires也是必不可少的

cache-control: max-age=3600, s-maxage=31536000

这里可以看到max-age的值                        ,它并不是一个时间戳,而是一个时间长度                 ,单位是秒                        ,意思是在3600秒内        ,该资源是有效的                 。max-age的机制就是对资源的判定有效不再受到服务器时间的限制                 ,客户端会记录到请求资源的时间点                        ,以此时间点为起点        ,从而确保两个时间点都来自于客户端         ,相对来说更加的精确                        ,这里就不给出请求图了                ,和上面原理一致

这里介绍下cache-control中的值

max-age:缓存保存的时间

no-cache:绕开了浏览器         ,每一次发起请求都不会再去询问浏览器的缓存情况                         ,而是直接向服务端去确认该缓存是否过期

no-store:不使用任何的缓存策略                ,连服务器端的缓存确认都绕开了,只允许直接向服务端发起请求                         ,并下载完整的响应

public:资源能被本地缓存                         、服务器代理

private:资源只能给本地缓存                        ,其他服务器不能缓存

协商缓存

浏览器向服务器询问是否需要重新下载资源,还是从本地上获取到缓存的资源                 ,值得一提的是                        ,当服务器提示资源未改动        ,资源就会被重定向到浏览器缓存                 ,对应的HTTP状态码是304

协商缓存的实现

Last-Modified:时间戳                        ,当我们第一次请求资源时        ,会在响应头中返回

If-Modified-Since:时间戳         ,就是服务器返回的Last-Modified的值

过程就是                        ,请求头会携带If-Modified-Since                ,服务器会进行判断         ,若If-Modified-Since的时间戳是和last-modified不一致                         ,服务器就会完整的返回响应内容                ,并且返回新的last-modified值,如果一致                         ,就返回304                        ,响应头也不会添加last-modified字段

第一次请求:

再次请求

但是last-modified有自己的缺陷

1                        、last-modified的值只精确到秒级

2、如果文件每隔一段时间重复生成,但内容是一致的                 ,last-modified会每次返回资源文件                        ,即使内容一致

所以etag对其进行了补充

Etag是服务器对每个资源文件生成的唯一 标识字符串         ,这个字符串基于文件内容编码                 ,只要文件内容不同                        ,对应的Etag也会不同

请求方式和上图差不多        ,服务器返回Etag         ,下次请求请求头会带上名为if-None-Match的字符串为服务器做对比

这里其实可以看到                        ,Etag会让服务器多做事                ,也就是会影响到服务器的性能         ,所以我们使用的时候需要进行考虑                         ,Etag的感知文件变化上比Last-modified更为准确                ,所以优先级也更高,二者同时出现时                         ,以Etag为准

上诉只是对HTTP缓存的一些简单介绍                        ,基础面试知识点可以应付了,HTTP缓存有很多知识                 ,感兴趣可以多百度看下

CSS篇

1                 、举出让元素居中的方法

个人总结出两种情况                        ,即需要居中的元素带宽高                        、不带宽高        ,如下:

带宽高 一 <style> .father { width: 500px; height: 500px; background-color: red; position: relative; } .son { width: 100px; height: 100px; background-color: blue; position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto; } </style> <body> <div class="father"> <div class="son"></div> </div> </body><style> .father { width: 500px; height: 500px; background-color: red; position: relative; } .son { width: 100px; height: 100px; background-color: blue; position: absolute; top: 50%; left: 50%; margin-top: -50px; margin-left: -50px; } </style> <body> <div class="father"> <div class="son"></div> </div> </body> 不带宽高 一 <style> .father { width: 500px; height: 500px; background-color: red; position: relative; } .son { background-color: blue; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); } </style> <body> <div class="father"> <div class="son">son</div> </div> </body><style> .father { width: 500px; height: 500px; background-color: red; display: flex; justify-content: center; align-items: center; } .son { background-color: blue; } </style> <body> <div class="father"> <div class="son">son</div> </div> </body>

2        、常见的布局方式

一                 、左边(右边)固定                 ,右边(左边)自适应 float布局 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> .left { width: 200px; height: 200px; background-color: red; float: left; } .right { height: 200px; background-color: blue; } </style> </head> <body> <div class="left"></div> <div class="right"></div> </body> </html> 绝对定位 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> .left { width: 200px; height: 200px; background-color: red; position: absolute; } .right { height: 200px; background-color: blue; } </style> </head> <body> <div class="left"></div> <div class="right"></div> </body> </html> 弹性布局 <!DOCTYPE html> <

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
网站优化怎么去做(网站优化的教程) coafeup牙膏(farbic plugin fexpect,bravo!)