前端面试小常识记录

前端面试题(JavaScript)

1、get 请求传参长度的误区

误区:我们经常说get 请求参数的大小存在限制,而post 请求的参数大小是无限制的。

实际上HTTP 协议从未规定GET/POST 的请求长度限制是多少。对get 请求参数的限制

是来源与浏览器或web 服务器,浏览器或web 服务器限制了url 的长度。为了明确这个

概念,我们必须再次强调下面几点:

HTTP 协议未规定GET 和POST 的长度限制

GET 的最大长度显示是因为浏览器和web 服务器限制了URI 的长度

不同的浏览器和WEB 服务器,限制的最大长度不一样

要支持IE,则最大长度为2083byte,若只支持Chrome,则最大长度8182byte

 

2、补充get 和post 请求在缓存方面的区别

post/get 的请求区别,具体不再赘述。

补充补充一个get 和post 在缓存方面的区别:

get 请求类似于查找的过程,用户获取数据,可以不用每次都与数据库连接,所以可以使用缓存。

post 不同,post 做的一般是修改和删除的工作,所以必须与数据库交互,所以不能使用缓存。因此get 请求适合于请求缓存。

 

3、说一下闭包

一句话可以概括:闭包就是能够读取其他函数内部变量的函数,或者子函数在外调用,子函数所在的父函数的作用域不会被释放

 

4、如何解决异步回调

promise、generator、async/await

 

5、说说前端中的事件流

HTML 中与javascript 交互是通过事件驱动来实现的,例如鼠标点击事件onclick、页面

的滚动事件onscroll 等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。

想要知道这些事件是在什么时候进行调用的,就需要了解一下“事件流”的概念。

什么是事件流:事件流描述的是从页面中接收事件的顺序,DOM2 级事件流包括下面几个阶段。

事件捕获阶段

处于目标阶段

事件冒泡阶段

addEventListener:addEventListener 是DOM2 级事件新增的指定事件处理程序的操作,这个方法接收3 个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。

IE 只支持事件冒泡。

 

6、说一下图片的懒加载和预加载

预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染。

懒加载:懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数。

两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。

懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。

 

7、mouseover 和mouseenter 的区别

mouseover:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是mouseout

mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是mouseleave

 

8、JS 的new 操作符做了哪些事情

new 操作符新建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象。

 

9、改变函数内部this 指针的指向函数(bind,apply,call 的区别)

通过apply 和call 改变函数的this 指向,他们两个函数的第一个参数都是一样的表示要

改变指向的那个对象,第二个参数,apply 是数组,而call 则是arg1,arg2...这种形式。通过bind 改变this 作用域会返回一个新的函数,这个函数不会马上执行。

 

10、JS 的各种位置,比如clientHeight,scrollHeight,offsetHeight ,以及scrollTop,

offsetTop,clientTop 的区别?

clientHeight:表示的是可视区域的高度,不包含border 和滚动条

offsetHeight:表示可视区域的高度,包含了border 和滚动条

scrollHeight:表示了所有区域的高度,包含了因为滚动被隐藏的部分。

clientTop:表示边框border 的厚度,在未指定的情况下一般为0

scrollTop:滚动后被隐藏的高度,获取对象相对于由offsetParent 属性指定的父坐标(css定位的元素或body 元素)距离顶端的高度。

 

11、Ajax 解决浏览器缓存问题

在ajax 发送请求前加上anyAjaxObj.setRequestHeader("If-Modified-Since","0")。

在ajax 发送请求前加上anyAjaxObj.setRequestHeader("Cache-Control","no-cache")。

在URL 后面加上一个随机数: "fresh=" + Math.random()。

在URL 后面加上时间搓:"nowtime=" + new Date().getTime()。

如果是使用jQuery,直接这样就可以了$.ajaxSetup({cache:false})。这样页面的所有ajax

都会执行这条语句就是不需要保存缓存记录。

 

12、JS 中的垃圾回收机制

必要性:由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他

们进行动态的存储分配。JavaScript 程序每次创建字符串、数组或对象时,解释器都必

须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript 的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。

这段话解释了为什么需要系统需要垃圾回收,JS 不像C/C++,他有自己的一套垃圾回收机制(Garbage Collection)。JavaScript 的解释器可以检测到何时程序不再使用一个对象了,当他确定了一个对象是无用的时候,他就知道不再需要这个对象,可以把它所占用的内存释放掉了。例如:

var a="hello world";

var b="world";

var a=b;

//这时,会释放掉"hello world",释放内存以便再引用

垃圾回收的方法:标记清除、计数引用。

标记清除

这是最常见的垃圾回收方式,当变量进入环境时,就标记这个变量为”进入环境“,从逻

辑上讲,永远不能释放进入环境的变量所占的内存,永远不能释放进入环境变量所占用

的内存,只要执行流程进入相应的环境,就可能用到他们。当离开环境时,就标记为离

开环境。

垃圾回收器在运行的时候会给存储在内存中的变量都加上标记(所有都加),然后去掉环境变量中的变量,以及被环境变量中的变量所引用的变量(条件性去除标记),删除所有被标记的变量,删除的变量无法在环境变量中被访问所以会被删除,最后垃圾回收器,完成了内存的清除工作,并回收他们所占用的内存。

引用计数法

另一种不太常见的方法就是引用计数法,引用计数法的意思就是每个值没引用的次数,当声明了一个变量,并用一个引用类型的值赋值给改变量,则这个值的引用次数为1,;相反的,如果包含了对这个值引用的变量又取得了另外一个值,则原先的引用值引用次数就减1,当这个值的引用次数为0 的时候,说明没有办法再访问这个值了,因此就把所占的内存给回收进来,这样垃圾收集器再次运行的时候,就会释放引用次数为0 的这些值。

用引用计数法会存在内存泄露,下面来看原因:

 

function problem() {var objA = new Object();var objB = new Object();objA.someOtherObject = objB;objB.anotherObject = objA;}

 

在这个例子里面,objA 和objB 通过各自的属性相互引用,这样的话,两个对象的引用次数都为2,在采用引用计数的策略中,由于函数执行之后,这两个对象都离开了作用域,函数执行完成之后,因为计数不为0,这样的相互引用如果大量存在就会导致内存泄露。特别是在DOM 对象中,也容易存在这种问题:

 

var element=document.getElementById(’‘);var myObj=new Object();myObj.element=element;element.someObject=myObj;

 

这样就不会有垃圾回收的过程。

 

13、对象深度克隆的简单实现

 

function deepClone(obj){var newObj= obj instanceof Array ? []:{};for(var item in obj){var temple= typeof obj[item] == 'object' ? deepClone(obj[item]):obj[item];newObj[item] = temple;}return newObj;}

 

ES5 的常用的对象克隆的一种方式。注意数组是对象,但是跟对象又有一定区别,所以

我们一开始判断了一些类型,决定newObj 是对象还是数组。

 

14、==和===、以及Object.is 的区别

(1) ==

主要存在:强制转换成number,null==undefined

" "==0 //true

"0"==0 //true

" " !="0" //true

123=="123" //true

null==undefined //true

(2)Object.js

主要的区别就是+0!=-0 而NaN==NaN

(相对比===和==的改进)

 

15、setTimeout、setInterval 和requestAnimationFrame 之间的区别

与setTimeout 和setInterval 不同,requestAnimationFrame 不需要设置时间间隔,

大多数电脑显示器的刷新频率是60Hz,大概相当于每秒钟重绘60 次。大多数浏览器都会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验也不会有提升。因此,最平滑动画的最佳循环间隔是1000ms/60,约等于16.6ms。

RAF 采用的是系统时间间隔,不会因为前面的任务,不会影响RAF,但是如果前面的

任务多的话,会响应setTimeout 和setInterval 真正运行时的时间间隔。

特点:

(1)requestAnimationFrame 会把每一帧中的所有DOM 操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率。

(2)在隐藏或不可见的元素中,requestAnimationFrame 将不会进行重绘或回流,这当然就意味着更少的CPU、GPU 和内存使用量

(3)requestAnimationFrame 是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU 开销。

 

16、实现JS 中所有对象的深度克隆(包装对象,Date 对象,正则对象)

通过递归可以简单实现对象的深度克隆,但是这种方法不管是ES6 还是ES5 实现,都有

同样的缺陷,就是只能实现特定的object 的深度复制(比如数组和函数),不能实现包

装对象Number,String , Boolean,以及Date 对象,RegExp 对象的复制。

(1)前文的方法

 

function deepClone(obj){var newObj= obj instanceof Array?[]:{};for(var i in obj){newObj[i]=typeof obj[i]=='object'?deepClone(obj[i]):obj[i];}return newObj;}

 

这种方法可以实现一般对象和数组对象的克隆,比如:

 

var arr=[1,2,3];var newArr=deepClone(arr);// newArr->[1,2,3]var obj={x:1,y:2}var newObj=deepClone(obj);// newObj={x:1,y:2}

 

但是不能实现例如包装对象Number,String,Boolean,以及正则对象RegExp 和Date 对象的

克隆,比如:

 

//Number 包装对象var num=new Number(1);typeof num // "object"var newNum=deepClone(num);//newNum -> {} 空对象//String 包装对象var str=new String("hello");typeof str //"object"var newStr=deepClone(str);//newStr-> {0:'h',1:'e',2:'l',3:'l',4:'o'};//Boolean 包装对象var bol=new Boolean(true);typeof bol //"object"var newBol=deepClone(bol);// newBol ->{} 空对象

 

....

(2)valueof()函数

所有对象都有valueOf 方法,valueOf 方法对于:如果存在任意原始值,它就默认将对象

转换为表示它的原始值。对象是复合值,而且大多数对象无法真正表示为一个原始值,

因此默认的valueOf()方法简单地返回对象本身,而不是返回一个原始值。数组、函数和

正则表达式简单地继承了这个默认方法,调用这些类型的实例的valueOf()方法只是简单

返回这个对象本身。

对于原始值或者包装类:

 

function baseClone(base){return base.valueOf();}//Numbervar num=new Number(1);var newNum=baseClone(num);//newNum->1//Stringvar str=new String('hello');var newStr=baseClone(str);// newStr->"hello"//Booleanvar bol=new Boolean(true);var newBol=baseClone(bol);//newBol-> true

 

其实对于包装类,完全可以用=号来进行克隆,其实没有深度克隆一说,

这里用valueOf 实现,语法上比较符合规范。

对于Date 类型:

因为valueOf 方法,日期类定义的valueOf()方法会返回它的一个内部表示:1970 年1 月

1 日以来的毫秒数.因此我们可以在Date 的原型上定义克隆的方法:

 

Date.prototype.clone=function(){return new Date(this.valueOf());}var date=new Date('2010');var newDate=date.clone();// newDate-> Fri Jan 01 2010 08:00:00 GMT+0800

 

对于正则对象RegExp:

 

RegExp.prototype.clone = function() {var pattern = this.valueOf();var flags = '';flags += pattern.global ? 'g' : '';flags += pattern.ignoreCase ? 'i' : '';flags += pattern.multiline ? 'm' : '';return new RegExp(pattern.source, flags);};var reg=new RegExp('/111/');var newReg=reg.clone();//newReg-> /\/111\//

 

 

17、JS 判断类型

判断方法:typeof(),instanceof,Object.prototype.toString.call()等

 

18、数组常用方法

push(),forEach(),pop(),shift(),unshift(),splice(),sort(),reverse(),map()等

 

19、数组去重

法一:indexOf 循环去重

法二:ES6 Set 去重;Array.from(new Set(array))

法三:Object 键值对去重;把数组的值存成Object 的key 值,比如Object[value1] = true,

在判断另一个值的时候,如果Object[value2]存在的话,就说明该值是重复的。

 

20、去除字符串首尾空格

使用正则(^\s*)|(\s*$)即可

 

21、性能优化

减少HTTP 请求

使用内容发布网络(CDN)

添加本地缓存

压缩资源文件

将CSS 样式表放在顶部,把javascript 放在底部(浏览器的运行机制决定)

避免使用CSS 表达式

减少DNS 查询

使用外部javascript 和CSS

避免重定向

图片lazyLoad

 

22、JS 基本数据类型

基本数据类型:undefined、null、number、boolean、string、symbol

 

23、跨域的原理

跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript 实施的安全限制,那么只要协议、域名、端口有任何一个不同,都被当作是不同的域。跨域原理,即是通过各种方式,避开浏览器的安全限制。

 

24、let const var 的区别,什么是块级作用域,如何用ES5 的方法实现块级作

用域(立即执行函数),ES6 呢

提起这三个最明显的区别是var 声明的变量是全局或者整个函数块的,而let,const 声明的变量是块级的变量,var 声明的变量存在变量提升,let,const 不存在,let 声明的变量允许重新赋值,const 不允许。

 

 

 
posted @ 2021-04-30 17:07  文博的博客  阅读(73)  评论(0编辑  收藏  举报