前端2021年面试题
Javascript面试题集
- 原生AJAX的工作步骤:
第一步:创建XHR对象 const xhr=new XMLHttpRequest();
第二步:打开客户端与服务端之间的连接 xhr.open(“get”,url,true);
第三步:客户端向服务端发送请求 xhr.send();
第四步:接受服务端返回的结果并进行处理 onreadystatechange事件,当readystate的值发生改变时,会触发该事件;readystate 用来表示服务器的处理进度,4表示服务端处理完成;status状态码 100-599,其中200表示成功 xhr.onreadstatechange=function(){
if(xhr.readyState4 && xhr.status200){
console.log(xhr.responseText)
}
} - ES6新特性有哪些
解构、扩展运算符、块级作用域(let、const)、类(class)、箭头函数、模板字符串: - 闭包
概念: 能够读取另一个函数作用域的变量的函数
作用:1、延长变量的声明周期;2、避免变量污染(命名冲突)
缺点:可能导致变量内存溢出
形成条件:1、函数之间形成嵌套;2、一个函数需要访问自身所在作用域中的数据;3、该函数在自身所在作用域以外被调用
原理:之所以形成闭包,就是因为一个函数在调用完成后,该函数的执行上下文在该销毁的时候,由于其他地方还有对该函数变量对象的使用,导致该函数的执行上下文销毁后,但内部的变量对象没有销毁,因此形成了闭包。
function foo() {
var a = 1;
function bar() { console.log(a); } return bar;
}
const result = foo();
result();
- 发送请求的方式
原生ajax、jquery封装的ajax、axios、fetch - get、post的区别:
get一般用于得到数据,post用于发送数据,post的安全性高于get,不会直接显示在地址栏里,但是get发送的请求速度更快。get传递的数据有大小限制,post没有 - javascript中有哪些会直接转换为布尔值false:
- false
、
0、空字符串(
"")、
NaN、
null和
undefined被转换为
false - 所有其他值被转换为
true
-
JavaScript中为什么null==0为false而null>=0为true?
在相等运算符中,null,undefined则不会转化为数字类型,而是经过特殊处理后转化为false(当然,除了与自身对比,或者是null与undefined对比,即都为true),在关系运算符中,null,undefined会被Number()强制转换成数字类型。 -
null和undefined的区别
null表示一个变量不在指向任何内存地址,undefined指申明的对象没有赋值
null==undefined null的typeof是object,undefined的typeof是undefined,所以null!===undefined
-
谈一下你对作用域的理解
作用域指的是标识符(函数、变量)能访问的范围,分为全局作用域和局部作用域(函数作用域、块级作用域(ES6 let、const) -
谈一下你对原型的理解
每个构造函数都有一个原型对象(prototype–显示原型),它上面有一个constructor属性,指向的是该构造函数本身,通过该构造函数new出来的实例对象,上面有一个_proto_
属性(隐式原型),它指向的是构造函数的原型对象
-
修改this指向的方法,以及区别
主要方法有三种call、apply、bind,区别:call、apply在改变函数this的同时,会立即执行,而bind在改变this指向后,会返回一个新函数需要重新调用;传参时call通过逗号分隔开,apply传参时,所有参数通过数组包裹起来
const student = {
name: 'zhangsan',
sayName: function (num) {
console.log(this);
console.log(num);
}}
const person = { name: 'lisi'}
student.sayName.call(person, 100);
student.sayName.apply(person, [100]);//修改this的指向,传参数时要用数组包裹
student.sayName.bind(person)(100);//修改this的向并同时再次调用
-
事件委托或事件代理的原理
事件冒泡 -
事件冒泡和事件捕获的区别
事件冒泡:是从目标事件传到windows对象,从下到上(domo级事件处理程序只能在冒泡阶段)
事件捕获:是从windows对象传到目标事件 -
如何用原生js给一个按钮的点击事件绑定两个事件处理函数
采用事件监听,addEventListener(‘click’,函数名,false),可以设置是在冒泡阶段还是捕获阶段绑定,默认值为false,
-
js异步编程有几种
有四种,分别为回调函数(缺点:会产生回调地狱,需要嵌套)、promise(ES6)、async await(ES7)、generator(ES6) -
promise有几种状态
promise有三种状态,分别为pending(等待中)、fulfilled(已成功)、rejected(已失败)
三个状态之间的变化,通过resolve将promise的状态从pending变成fulfilled,调用reject将promise的状态从pending变成rejected。 -
js数据类型有哪些、以及有什么区别
-
js如何浅拷贝和深拷贝一个对象
浅拷贝:Object.assign(),也可以使用扩展运算符
深拷贝:浅拷贝+递归,还有一种方法const deepCopiedObj = JONS.parse(JSON.stringify(obj))
-
for循环中break和continue的区别
break是结束该循环,continue是结束本次循环开始下次循环 -
js引擎是如何实现异步的
所有的js代码都是在执行栈里面执行的,在执行代码的过程中如果遇到异步任务(比如发送请求),则把异步任务交给浏览器的其他线程(http请求线程)去处理,js引擎则继续完后执行任务,注意:这是浏览器的其他线程(http请求线程)和js引擎线程是在同步执行任务的,当http请求线程把异步任务处理完成之后(接口发送成功,拿到返回的数据)它就会把我们之前设置的回调函数推送js引擎中的任务队列。同时当执行栈里面的任务被清空之后,js引擎则会到任务队列里面去找,有没有待执行的回调函数,如果有,则立即拿到执行栈中执行,当执行栈中任务执行完了之后,又会到任务队列中去找有没有待执行的回调函数,有,就立即拿到执行栈中执行,如此循环往复,就形成我们所讲的事件循环(event-loop),你理解了事件循环,就理解了js引擎如何实现异步。 -
微任务和宏任务的区别
异步任务可以分为微任务(Micro task)和宏任务(Macro task),微任务有:promise 、queueMicrotask,宏任务有:settimeout、setinterval区别:微任务的优先级高于宏任务;(可以理解为当执行栈里的代码执行完后开始执行任务队列(异步任务)里的代码,先执行微任务,后执行宏任务 -
什么是函数柯里化
通过函数返回函数的方式(闭包),让一个一次性接受多个参数的函数,分解为一次只接受一个参数的若干函数的组合
作用:参数的复用
//正常函数
function twoSum(a,b){
return a+b
}
const total=twoSum(1,2)
//函数柯里化
function twoSumk(a){
return function(b){
return a+b
}
}
const t=twoSumk(1)(2)
//例如要计算1和2、1和3、1和5、1和10的和
const func=twoSumk(1)//返回的是一个函数
func(2);
func(3);
func(5);
func(10);
-
DomContentLoaded和load事件的区别
load事件:等到页面所有的资源(html、js、css、图片)等加载完成后才会执行
DomContentLoaded事件:Dom加载完就执行的
区别:执行时机DomContentLoaded要早一些 -
浏览器渲染页面的流程
GUI渲染线程负责界面的渲染过程同时解析html/css解析html ---->DOMTree,解析css—>CSSTree,然后合并DOMTree和CSSTree形成RenderTree(渲染树),接下来开始layout (布局,回流),绘制(重绘)
根据这些过程我们可以知晓在写html的时候需要注意的一些事项(性能优化)css放在头部,js放在尾部,因为js是有js引擎去编译和执行的,而js引擎和GUI渲染引擎是互斥的 -
如何中断ajax请求
两种设计思路,一种是设置超时时间让ajax自动断开,另一种是手动停止ajax请求,其核心是调用XML对象的abort方法,ajax.abort() -
target与currentTarget的区别
currentTarget当前所绑定事件的元素,target当前被点击的元素 -
js继承有哪些方式:
主要有三种,原型链继承、构造继承、实例继承、组合继承
原型链继承核心:将父类的实例作为子类的原型
构造函数继承核心:使用父类的构造函数来增强子类实例,等于复制父类的实例属性给子类
实例继承核心:为父类实例添加新特性,作为子类实例返回
组合继承核心:通过调用父类构造函数,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用 -
export与export default的区别
用export暴露出去的,要用import {} from ""
来引入;
用export default暴露出去的,要用import xx from ''
来引入 -
typeof与instance of检测数据类型有什么区别
相同点:都常用来判断一个变量是否为空,或者为什么类型的数据
不同点:typeof返回值是一个字符串,用来说明变量的数据类型;instance of用于判断一个变量是否属于某个对象的实例 -
new的原理是什么?通过new的方式创建对象和通过字面量创建有什么区别
new的原理:创建一个对象,这个对象会被执行原型连接;将构造函数的作用域赋值给新对象,即this的指向这个新对象;如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象
字面量创建对象,不会调用Object构造函数,简洁且性能更好 -
如何判断一个是数组还是对象
var arr = []
arr instanceOf Array
//true
typeof arr
//object,typeof是无法判断是否是数组的
通用判断方法:Object.prototype.toString.call(arr) === "[object Array]"
-
let、const、var定义的区别
-
typeof能判断的类型
-
什么是纯函数
返回值只和函数参数有关,与外部无关。无论外部发生什么样的变化,函数的返回值都不会改变。 -
什么是立即执行函数(IIFE)
定义: 立即执行函数就是声明一个匿名函数,然后马上执行这个匿名函数
立即执行函数形成条件: 一是函数体后面要有小括号(),二是函数体必须是函数表达式而不能是函数声明 ;
注明:除了用小括号之外, !,+,-,=等运算符都能起到立即执行的作用 , 这些运算符的作用就是将匿名函数或函数声明转换为函数表达式
好处: 通过定义一个匿名函数,创建了一个新的函数作用域,相当于创建了一个“私有”的命名空间,该命名空间的变量和方法,不会破坏污染全局的命名空间。
函数分为声明式函数、函数表达式、匿名函数 -
什么是递归函数
自己调用自己的函数,为防止成死循环需设置边界条件 -
dom里操作节点的方法
-
清空数组的方式
长度设置为,或者等于空数组。 -
Dom0级和dom2级区别
Dom0级事件流在冒泡阶段,只能绑定一个事件,后面的事件会覆盖前面地,兼容性比较好
Dom2级既可以在冒泡阶段也可以在捕获阶段,通过true或fasle来控制,可以绑定多个事件,但是兼容性不高 -
return在函数中的作用
若是在函数中没写return或return后面不写任何结果,那么函数的返回结果是undefined -
数组去重和排序