• 前端面试小常识记录


    前端面试题(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 不允许。

     
  • 相关阅读:
    xtrabackup原理1
    mydumper原理3
    mydumper原理1
    mydumper原理2
    MYSQL数据库管理之权限管理
    percona-toolkit工具包的使用教程
    Percona-Galera-Monitoring-Template监控模板说明
    mysql优化--博森瑞
    percona-toolkit -1
    innobackupex --slave-info参数的含义和适用场景
  • 原文地址:https://www.cnblogs.com/wenbodeboke/p/14722718.html
Copyright © 2020-2023  润新知