前端面试题整理—JavaScript篇(一)
1、JS的基本数据类型和引用数据类型有哪些,两者区别
基本数据类型->string、number、Boolean、null、undefined、symbol
引用数据类型->array、object、function
基本数据类型是保存在栈内存中,操作的是值,改变源数据不会影响新的变量
引用数据类型保存在堆内存中,操作的是地址,改变其中一个会影响另一个
2、数据类型中为假的有哪些?
false (布尔型)
0(数值型)
null(定义空的或者不存在,现在没有,将来可能有)
undefined(未定义,一直不存在)
NaN(不是一个有效数字)
空字符串(空字符串,字符类型)
3、举例JavaScript的基本规范,以及如何编写高性能代码
基本规范
1)代码缩进,建议使用“四个空格”缩进
2)语句结束使用分号
3)变量和函数在使用前进行声明
4)以大写字母开头命名构造函数,全大写命名常量
5)使用ID最好先获取一下
6)规范定义JSON对象,补全双引号
1)遵循严格模式:"use strict";
2)将js脚本放在页面底部,加快渲染页面
3)尽量减少使用闭包
4)尽量使用直接量创建对象和数组
5)尽量减少对象成员嵌套
6)最小化重绘(repaint)和回流(reflow)
4、JS有哪些内置对象
Object、Array、Boolean、Number、String、Function、Arguments、Math、Date、RegExp
ES6新增对象:Symbol、Map、Set、Promises、Proxy
5、怎么实现string和number的相互转换
String 转换成 Number:Number()、parseInt()、parseFloat()
Number 转换成 String:String()、toString()
6、怎么创建、添加、替换、克隆、删除元素
创建-> document.createElement('标签名')
添加-> parent.appendChild()
parent.insertBefore(新插入的元素,老元素)
替换-> replaceChild(new,old)
克隆-> cloneChild()
删除->removeChild()
7、什么情况下会转为字符串
1)基于alert、confirm、document.write等输出内容时,会先把值转为字符串后在输出
2)基于'+'进行字符串拼接时
3)把复合类型值转换数字时候。首先会转换字符串然后再转为数字
4)给对象设置属性名时候,如果不是字符串 先转为字符串,然后在作为属性存储到对象中(对象属性只能是字符串和数字)
5)手动调用toString、toFixed(将 Number 四舍五入为指定小数位数的数字)、join、String方法时候,也是为了转换字符串
8、获取对象属性[]和.的区别
.后面的是这个对象的属性,凡是用.的地方都可以用[]
[]中括号的内容可以是字符串也可以是变量,基本上[]放的是变量
9、null和undefined的区别
Null:代表空对象指针。现在没有,将来可能会有
undefined:空,未定义。现在没有,将来也不会有(Js中独有的数据类型)
10、检测数据类型的几种方式,以及他们的对比
typeof、instanceof、constructor、Object.prototype.toString.call()
typeof只针对基本数据类型,遇到引用数据类型是不起作用的(无法细分对象)
instanceof用来判断对象和函数,不适合判断字符串和数字
constructor是Object其中的一个属性。默认指向实例的构造函数
通过Object.prototype.toString方法,判断某个对象值属于哪种内置类型
11、in 与 hasOwnProperty
两者都代表查看某个属性是不是自己的
in判断的是对象的所有属性,包括对象实例及其原型的属性
hasOwnProperty则是判断对象实例的是否具有某个属性
12、innerHTML和innerText区别
innerHTML可以获取结构和文本
innerText只获取文本内容
13、如何清除一个定时器?
clearTimeout(timer)
14、说一下倒计时原理及公式
未来时间-现在时间= 剩余时间
let d = Math.floor(t/86400); t % =86400; let h = Math.floor(t/3600); t % = 3600; let m = Math.floor(t/60); t % = 60;
15、何时使用 === 何时使用 ==
判断对象的属性是否存在可以使用双等,其余都用全等
===更严谨,不仅值相等类型也要相等,不用进行类型转换,并且比==速度快
16、eval 是做什么的?
它的功能是把对应的字符串解析成JS代码并运行
由JSON字符串转换为JSON对象的时候可以用 eval('('+ str +')');
应避免使用eval,因为不安全,耗性能
17、数组常用的一些方法有哪些
push()向数组末尾添加数据
pop()删除数组最后一项
unshift()向数组首位添加新内容
shift()删除数组的第一项
slice()按照条件查找出其中的部分内容
splice()对数组进行增删改
join()用指定的分隔符对数组拼接
concat()用于连接两个或多个数组
indexOf()/lastIndexOf()当前值在数组中第一次/最后一次出现的位置索引
includes()判断一个数组是否包含指定的值
sort()对数组进行排序
reverse()把数组倒过来排列
forEach()循环遍历数组每一项
18、说一下什么是DOM映射机制
通过DOM中方法获取到的元素,与页面一一对应的这种关系称之为DOM映射
querySelectorAll获取到的元素集合没有DOM映射,必须是元素的内置属性发生变化,浏览器才能监听得到
19、一行代码实现数组去重
[...new Set([1,2,3,4])]
20、节点类型都有哪些,如何判断当前节点类型
1元素节点,2属性节点,3文本节点,8注释节点、9文档节点
通过nodeObject.nodeType判断节点类型,其中,nodeObject为节点对象
该属性返回以数字表示的节点类型,例如,元素节点返回1,属性节点返回2
21、重绘和回流(重排)区别,什么情况会触发重排和重绘
当页面元素(宽高,位置)发生改变,回导致页面重排,浏览器会根据新位置进行重新渲染
回流必将引起重绘,而重绘不一定会引起回流。重绘相对于回流性能消耗较低
任何改变用来构建渲染树的信息都会导致一次重排或重绘
比如添加、删除、更新DOM节点,通过display: none隐藏,调整样式属性,调整窗口大小,滚动等等
22、如何最小化重绘(repaint)和回流(reflow)
1)需要对元素进行复杂的操作时,可以先display:none隐藏,操作完再显示
2)需要创建多个DOM节点时,使用DocumentFragment创建完后一次性的加入document
3)尽量避免用table布局
4)避免使用css表达式(expression),每次调用都会重新计算值(包括加载页面)
5)尽量使用css简写,如:用border代替border-width,border-style, border-color
23、什么是自执行函数,用于什么场景
自执行函数,即定义和调用合为一体,比如匿名函数自执行
他可以创建一个独立作用域,防止作用域污染,防止变量影响到全局,以免产生冲突
多用于框架和插件
24、改变this指向的方法
call、apply、bind
call和apply可以自动执行,bind需要手动调用,返回值为函数
call和bind都有无数个参数,apply只有两个参数,并且第二个为数组
25、iframe的优缺点
优点:
1)iframe能够原封不动的把嵌入的网页展现出来
2)头部和底部一样时可以写成一个页面,用iframe来嵌套,可以增加代码的可重用
3)引用多个页面,只需要修改iframe的内容,就可以实现页面内容的更改
缺点:
不容易管理、用户体验度差、不利于搜索引擎优化、兼容性差、增加服务器的http请求,一般用Ajax来代替iframe
26、类数组转数组的方法
Array.from
Array.prototype.slice.call
[].slice.call
27、请解释什么是暂时性死区
let 和 const 声明的变量不存在变量提升,其作用域都是块级作用域,凡是在声明变量之前使用变量就会报错,
所以,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”
28、严格模式与非严格模式的区别
非严格模式又被被称为懒散模式
严格模式 use strict是一种ECMAscript 5添加的运行模式,这种模式使得 Js在更严格的条件下运行,使JS编码更加规范化
消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为。
严格模式中变量必须显示声明
在严格模式下,arguments和eval是关键字,不能被修改
在严格模式下,函数的形参也不可以同名
29、验证手机号码和邮箱的正则表达式
手机号码验证
/^(13[0-9]|14[5-9]|15[012356789]|166|17[0-8]|18[0-9]|19[8-9])[0-9]{8}$/
邮箱验证
^[A-Za-z]\w{3,17}@[1-9A-Za-z]{2,8}\.(com|cn|net)$
30、window 和document常见的方法和属性
Window对象常见的属性:
top 代表当前所有窗口的最顶层窗口
parent 指当前窗口的父窗口
self 指当前窗口
status 指定当前窗口状态栏中的信息
Window对象常见的方法:
alert 显示带有一个“确定”按钮的对话框
confirm 显示带有“确定”和“取消”两个按钮的对话框
open 打开一个新的窗口
close 关闭用户打开的窗口
Document常见属性:
title 设置文档标题,也就是html的标签
bgColor 设置页面的背景色
URL 设置url属性
fileSize 文件大小
Document常见的方法:
write() 动态向页面写入内容
createElement(Tag) 创建一个HTML标签
getElementById(ID) 获得指定id的对象
getElementsByName(Name) 获得之前Name的对象
31、如何添加HTML元素的事件,有几种方法
标签之中直接添加 onclick="fn()"
JS添加 btn.onclick = method
绑定事件 obj.addEventListener('click', method, false)
32、使用js去除字符串空格
str.trim()
使用replace正则匹配:str.replace(/\s*/g,"")
33、什么是闭包,有什么优缺点
在Js中当函数套函数,子函数使用了父函数的参数或者变量,并且子函数被外界所使用(没有释放),
此时父函数的参数和变量,是不会被浏览器垃圾回收机制立马收回,这个时候父级形成了闭包环境。
function fn(){ let a = 10; return function(){ console.log(a); } } let f = fn(); console.dir(f);// 控制台中的closure就代表闭包
优点:
保护—闭包会形成私有作用域,保护里面的私有变量不受外界干扰
存储—闭包可以把父函数的参数或变量存储起来
缺点:
相对于普通函数要消耗内存,闭包使用不当将会在IE(IE9之前)中造成内存泄漏
34、理解的JavaScript垃圾回收机制
Js具有自动垃圾回收机制。垃圾收集器会按照固定的时间间隔周期性的执行
垃圾回收机制主要有两种方法:
1、标记清除法
打开页面时,先把所有的变量打上标记,然后把被使用的变量清除标记。如果下次查询之前标记的没有被引用,此时就回收
2、引用计数法
变量每用一次就记录一次,一开始为0,下次引用+1,每少用一次就-1。当变为0时候 就清空回收
直接给变量赋值一个null的地址可以解决闭包消耗的内存
35、什么情况会引起内存泄漏,产生原因及解决方案?
1)意外的全局变量引起的内存泄漏
原因:全局变量,不会被回收
解决:可以使用严格模式避免
2)闭包引起的内存泄漏
原因:闭包可以维持函数内局部变量,使其得不到释放
解决:将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中,删除对dom的引用
3)没有清理的DOM元素引用
原因:虽然别的地方删除了,但是对象中还存在对dom的引用
解决:手动删除即可
4) 忘记的定时器或者回调
原因:定时器中有dom的引用,即使dom删除了,但是定时器还在
解决:手动清除定时器和dom
36、什么是原型,什么是原型链,两者关系
原型(prototype):函数自带的属性,函数的实例化对象找不到某个属性或者方法,一定会去构造函数的原型下去找
原型链(__proto__):实例化对象身上自带一个属性
原型关系链:函数的实例化对象找不到某个属性或方法,一定会去构造函数的原型下去找,如果还没有会去原型下的原型链查找,直到找到Object.prototype为止
两者关系:实例化对象的原型链 === 构造函数的原型
37、如何合并两个数组
//第一种 var arr1=[1,2,3]; var arr2=[4,5,6]; arr1 = arr1.concat(arr2); console.log(arr1); //第二种 var arr1=[1,2,3]; ar arr2=[4,5,6]; Array.prototype.push.apply(arr1,arr2); console.log(arr1);
38、简述this出现的情况
1)全局下的this是window
2)单纯的函数名+括号执行,this是window
3)匿名函数自执行,this是window
4)定时器中的this是window
5)事件触发,触发谁this就是谁
6)对象方法中,.前面是谁 this就指向谁
7)构造函数中this是实例化对象
8)严格模式下this是undefined
9)箭头函数中this指向上一级
10)箭头函数中this暴露在外面就指向window
39、函数声明和函数表达式的区别
fn() //不会报错 function fn(){ //声明 } fn1() //会报错:fn1 is not a function var a = function(){ //表达式 }
40、说一下对变量提升的理解
在某一作用域中,声明变量的语句会默认解析,在该作用域的最开始就已经声明了
41、Js有哪些解决异步的方案
1)callback 回调函数
2)promise
3)事件监听
4)async await
42、new之后发生了什么
使用new之后不用加括号一样会执行函数
new之后this变为实例化对象
默认返回值就不是undefined而是实例化对象
写了return,如果return后面是简单类型,返回结果依然是实例化对象,如果是复合类型,返回结果则是这个复合类型
43、写一个原生的xhr请求过程,readystate的几种状态 分别什么含义?
let xhr = new XMLHttpRequest(); xhr.open('get','./package.json'); xhr.onreadystatechange = function () { if(xhr.readyState == 4 && xhr.status == 200) { let result = JSON.parse(xhr.responseText); console.log(result.name) } }; xhr.send()
readyState的几种状态
0:请求未初始化(此时还没有调用open)
1:服务器连接已建立,已经发送请求开始监听
2:请求已接收,已经收到服务器返回的内容
3:请求处理中,解析服务器响应内容
4:请求已完成,且响应就绪
44、什么是作用域、作用域链
作用域分为全局作用域、局部作用域(包括es6新增块级作用域)
简单理解作用域就是一个独立的空间,让变量不会暴露。不同作用域下同名变量不会冲突
当前作用域未定义的变量(自由变量)会向父级作用域查找,如果父级没有再一层层往上找,直到全局作用域,这种一层层的关系称为作用域链
45、浅拷贝和深拷贝,实现的几种方式
浅拷贝只复制某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存
深拷贝会开辟一个新的栈,新对象跟原对象不共享内存,修改新对象不影响原对象
简单来说假如B复制了A,当修改A时候B如果跟着改变就是浅拷贝,B没有改变则为深拷贝
浅拷贝实现方式:
Object.assign()、Array.prototype.concat()、Array.prototype.slice()
深拷贝实现方式:
JSON.parse(JSON.stringify())、手写递归、jquery的$.extend
46、声明变量和声明函数的提升有什么区别
变量声明提升:变量申明在进入执行上下文就完成了
只要变量进行声明,无论在哪个位置,js引擎都会将它的声明放在作用域的顶部
函数声明提升:执行代码之前会先读取函数声明,可以把函数申明放在调用它的语句后面
函数声明会覆盖变量声明,但不会覆盖变量赋值
47、说一下变量提升机制
关于变量提升:
无论条件成不成立都会先进行预解析
匿名函数不会预解析
es6不存在变量提升
预解析的函数只解析一次(再遇到就会跳过)
变量提升机制:
一、变量提升
1)先找var进行提升,赋值undefined,变量名一样,后者覆盖前者
2)遇见函数,把函数名提升,赋值整个代码块
函数名同名,后者覆盖前面,只看最后一个函数即可
3)变量名与函数名同名情况下,最终留下代码块
如果是函数声明,就只解读一次,遇到别的直接跳过
函数表达式是带等号的所以会解读
二、逐行解读代码
只看带有等号的,如果有赋值,这个变量就是被赋值的值
就算下面有函数声明也不会继续看了
48、平时怎么样进行数据交互?如果后台没有提供数据怎么进行开发?mock数据与后台返回的格式不统一怎么办?
由后台编写接口文档、提供数据接口实、前台通过ajax访问实现数据交互;
在没有数据的情况下寻找后台提供静态数据或者自己定义mock数据
返回数据不统一时编写映射文件 对数据进行映射
49、什么是回调函数
回调函数callback,就是一个函数执行完后立刻执行另一个
它与箭头函数不一样的是,它会拿返回的值作为参数
50、什么是构造函数?与普通函数有什么区别
构造函数:是一种特殊的方法、主要用来创建对象时初始化对象,总与new运算符一起使用。创建对象的语句中构造函数的函数名必须与类名完全相同
与普通函数相比只能由new关键字调用,构造函数是类的标示
51、ajax 和 jsonp区别
相同点:都是请求一个url
不同点:ajax的核心是通过xmlHttpRequest获取内容
jsonp的核心则是动态添加<script>标签来调用服务器 提供的js脚本
52、JavaScript 有哪几种创建对象的方式?
1)对象字面量的方式
2)用function来模拟无参的构造函数
3)用工厂方式来创建(内置对象)
4)用原型方式来创建
53、举例ES5数组新增的哪些方法
1)forEach() 专门用来遍历数组
2)map() 将调用的数组中每个元素传递给指定的函数,并返回一个新数组
3)filter() 过滤,返回满足条件的元素组成的新数组
4)every()所有元素满足条件就返回true,有一个不满足条件就返回false
5)some()所有元素只要有一个满足条件就返回true,都不满足条件就返回false
6)reduce()累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值
54、获取随机数,要求是长度一致的字符串格式
var random = Math.random() + '0000000000'; var random = random.slice(0,10);
55、移动端点击事件300ms延迟如何去掉,产生原因
产生原因:
移动端会有双击缩放的这个操作,因此浏览器在click之后要等待300ms,看用户有没有下一次点击(也就是这次操作是不是双击)
解决方法:
1)禁用缩放
<meta name="viewport" content="user-scalable=no"> <meta name="viewport" content="initial-scale=1,maximum-scale=1">
2)更改默认的视口宽度
<meta name="viewport" content="width=device-width"/>
3)使用fastClick插件
window.addEventListener( "load", function() { FastClick.attach( document.body ); }, false );
56、let有什么用,有了var为什么还要用let ?
ES6之前,声明变量只能用var,他有一些不合理的地方。
let声明的变量拥有自己的块级作用域,且修复了var声明变量带来的变量提升问题
57、请描述一下对事件冒泡、事件捕获、事件流的理解,怎么阻止冒泡
事件冒泡:就是从目标元素自下而上一直到window(结束)这样一个过程
事件捕获:就是从window自上而下一直到目标元素的这样一个过程
一般是先执行捕获,后执行冒泡
事件流:当一个事件触发时候,一般会经历3个过程,第一个为捕获阶段,第二个为目标阶段,第三个为冒泡阶段这么一个过程
使用stopPropagation() 和 cancelBubble阻止冒泡
58、什么是事件委托,有什么好处
事件委托又叫事件代理。利用冒泡的原理,把事件加到父级上,触发执行效果
好处:新添加的元素还会有之前的事件;提高性能
59、拖拽会用到哪些事件?
使用onmousedown、onmousemove、onmouseup来实现
60、什么是移动端点透事件,如何解决
一个元素下有焦点(比如a 、input)在300毫秒之内让上层元素消失,这时手机会记录按下的位置并进行监听(是否触发两次)
因为要监听是否双击,在第一次按下时捕捉到了坐标,正好坐标下有焦点元素,此时就会触发焦点元素
解决方案:
1、在上层元素消失时候延迟执行
2、不使用焦点元素。比如以div代替a
3、在touch事件里面调用e.preventDefault() 进行阻止
61、简述一下你理解的面向对象
把相同的代码抽象出来归为一类,把描述特征的功能挂在这个类的原型上的一种设计编程思想
面向对象具有封装性,继承性,多态性。提高了大型程序的重用性和可维护性
62、如何获取hash,并设置一个hash
window.location.hash
window.location.hash = 'p=0';
63、js延迟加载的方式有哪些
defer和async、动态创建DOM方式、按需异步载入js
64、什么是事件默认行为,如何阻止
当用户触发某个事件的时候,某种行为不是我们主动写的而是浏览器默认就有的事件
阻止:
DOME0:return false
DOME1:ev.preventDefault
65、列举js常用的事件
onmouseover鼠标移入、onmouseout鼠标移出
onmouseenter鼠标穿过、onmouseleave鼠标离开
onmousemove鼠标移动、onmousewheel 鼠标滚轮
onclick点击、oncontextmenu右击菜单
onchange改变内容、onfocus获取焦点、onblur失去焦点
onresize改变窗口、onload加载完成
onkeyup键盘抬起、onkeydown键盘按下
66、构造函数、原型对象、实例对象三者的关系
三者的关系是,每个构造函数都有一个原型对象,原型对象上包含着一个指向构造函数的指针,而实例都包含着一个指向原型对象的内部指针。
通俗的说,实例可以通过内部指针访问到原型对象,原型对象可以通过constructor找到构造函数
67、Js中,有一个函数,执行对象查找时,永远不会去查找原型,这个函数是哪个
hasOwnProperty
该函数方法返回一个布尔值,指出一个对象是否具有指定名称的属性。此方法无法检查该对象的原型链中是否具有该属性;该属性必须是对象本身的一个成员
68、Canvas和SVG的比较
canvas是一个标签(canvas)+一个对象(getcontext),所有图形图像都靠ctx绘制
SVG几十个标签-每个图形对应一个标签
canvas位图技术,可以保存为.png,SVG矢量图技术,不能保存为位图
canvas不能被搜索引擎爬虫所访问,SVG可以
只能为整个Canvas绑定监听函数,SVG每个图形(标签)都可以绑定事件监听函数
69、如何规避javascript多人开发函数重名问题
(1) 可以开发前规定命名规范,根据不同开发人员开发的功能在函数前加前缀
(2) 将每个开发人员的函数封装到类中,调用的时候就调用类的函数,即使函数重名只要类名不重复即可
70、Cookie、Session、WebStorage的区别
cookie:用来保存客户浏览器请求服务器页面的请求信息,大小4KB
session:是一种服务器端的机制,服务器使用一种类似于散列表的结构来保存信息
WebStorage提供了localStorage、sessionStorage两种API,大小都在5M
cookie数据存放在客户的浏览器上,session数据放在服务器上
cookie不是很安全,别人可以分析存放在本地的cookie
session会在一定时间内保存在服务器上。当访问增多,会占用服务器的性能
cookie:可以通过expires设置失效时间,不设置默认关闭浏览器即失效
localStorage:除非手动清除,否则永久保存
sessionStorage:仅在当前会话时候生效,关闭页面即失效
71、什么是柯里化函数
柯里化(Currying)就是把接收多个参数的函数转换成一个单个参数的函数
并且返回接收余下的参数。返回结果是一个新函数
函数柯里化的主要作用和特点是参数复用、提前返回和延迟执行
72、如何理解防抖和节流
防抖:短时间内连续触发的事件,在某个时间期限内事件函数只执行一次
节流:如果短时间内大量触发同一事件,在函数执行一次之后,在指定的时间期限内不再工作,直至过了这段时间才重新生效
73、什么是单例模式,什么是工厂模式
单例模式:把描述同一个事物的属性和方法放在一个内存空间下,起到分组的作用
这样不同事物之间的属性即使同名也不会冲突。单例模式实例化出来的对象是唯一的
工厂模式:把相同代码封装起来,实现批量生产目的的一种模式。减少冗余代码
74、举例几种常用的Object方法
Object.assign()、Object.create()
Object.defineProperty、Object.prototype.hasOwnProperty
75、js实现继承的几种方式
1)类式(call)继承
2)拷贝继承
3)原型继承
4)寄生组合式继承
5)es6中class继承