JS面试题
- js基本类型和引用类型
- 说说写JavaScript的基本规范?
- js如何判断一个对象是数组
- 怎么判断两个对象相等
- "=="和"==="的不同
- js对数组操作的常用方法有哪些?
- split() join() 的区别
- js 拷贝
- 原型和原型链
- 什么是闭包
- 事件循环机制(event loop)
- require和import区别
- 怎么理解js中的内存泄露
- js延迟加载的方式有哪些?
- 如何阻止事件冒泡
- 浅谈setTimeout 和 setInterval
- JavaScript作用域链
- Ajax使用
- 谈谈this的理解
- 什么是window对象? 什么是document对象?
- null,undefined的区别?
- new操作符具体干了什么呢?
- 同步和异步的区别?
- 回流与重绘
- DOM操作
- 数组对象有哪些原生方法,列举一下
- 哪些操作会造成内存泄漏
- 请描述一下cookie,sessionStorage和localStorage的区别
- http状态码有那些?分别代表是什么意思?列举2-3个熟悉的状态码
- 一个 http 请求由什么组成?
- http 协议的 三次握手/四次挥手,可以描述一下吗?
- ajax请求的时候get 和post方式的区别?
- 什么是防抖和节流?有什么区别?如何实现?
js面试题解析
js基本类型和引用类型
- null(空)
- undefined(未声明)
- number(数字)
- string(字符串)
- object(对象)
- boolean(布尔值)
- symbol(符号,es6新增)
基本数据类型:Undefined、Null、Boolean、String、Number、Symbol (es6)。
引用类型:Object。Object可以细分为:Object 类型、Array 类型、Date 类型、RegExp 类型、Function 类型
说说写JavaScript的基本规范?
- 不要在同一行声明多个变量
- 使用 ===或!==来比较true/false或者数值
- switch必须带有default分支
- 函数应该有返回值
- for if else 必须使用大括号
- 语句结束加分号
- 命名要有意义,使用驼峰命名法
js如何判断一个对象是数组
1.typeof操作符
- 利用typeof除了array和null判断为object外,其他的都可以正常判断
2.instanceof操作符
var arr = [1,2,3,1];
console.log(arr instanceof Array); // true
var fun = function(){};
console.log(fun instanceof Function); // true
3.对象的constructor 属性
var arr = [1,2,3,1];
console.log(arr.constructor === Array); // true
var fun = function(){};
console.log(arr.constructor === Function); // true
4.使用 Object.prototype.toString 来判断是否是数组
Object.prototype.toString.call( [] ) === ``'[object Array]'` `// true`
Object.prototype.toString.call( ``function``(){} ) === ``'[object Function]'` `// true
这里使用call来使 toString 中 this 指向 obj。进而完成判断
5.Array.isArray()
Array.isArray([]) ``// true
6.使用 原型链 来完成判断
[].__proto__ === Array.prototype ``// true` `var` `fun = ``function``(){}``fun.__proto__ === Function.prototype ``// true
怎么判断两个对象相等
JSON.stringify(obj)==JSON.stringify(obj); //true
"=="和"==="的不同
- 前者会自动转换类型,再判断是否相等
具体如下:
一、首先看双等号前后有没有NaN,如果存在NaN,一律返回false。
二、再看双等号前后有没有布尔,有布尔就将布尔转换为数字(false是0,true是1)
三、接着看双等号前后有没有字符串, 有三种情况:
1、对方是对象,对象使用toString()或者valueOf()进行转换;
2、对方是数字,字符串转数字;(前面已经举例)
3、对方是字符串,直接比较;
4、其他返回false
四、如果是数字,对方是对象,对象取valueOf()或者toString()进行比较, 其他一律返回false
五、null, undefined不会进行类型转换, 但它们俩相等- 后者不会自动类型转换,直接去比较
js对数组操作的常用方法有哪些?
1、shift():删除原数组第一项,并返回删除元素的值;如果数组为空则返回undefine。这里是0
2、unshift(3,4):把参数加载数组的前面,并返回新数组长度。现在list:中是3,4,0,1,2
3、pop():删除最后一项,并返回删除元素的值;如果数组为空则返回undefine。这里是2.
4、push(3):将参数加载到数组的最后,并返回新数组长度,现在List中时:0,1,2,3
5、concat(3,4):把两个数组拼接起来,返回合并后的新数组,原数组木变。
6、splice(start,deleteCount,val1,val2,...):从start位置开始删除deleteCount项,并从该位置起插入val1,val2,...
7、reverse:并返回翻转后的原数组,原数组翻转了
8、sort(orderfunction):按指定的参数对数组进行排序 var a = [1,2,3,4,5]; var b = a.sort(); //a:[1,2,3,4,5] b:[1,2,3,4,5]
9、slice(start,end):返回从原数组中指定开始下标到结束下标之间的项组成的新数组,原数组木变,索引从0开始
10、join 将数组转换成字符串并返回字符串.将数组中所有元素以参数作为分隔符放入一个字符,原数组木变
11、indexOf 数组元素索引,并返回元素索引,不存在返回-1,索引从0开始
改变原数组的:
shift,unshift,pop,push,reverse,sort,splice
不改变原数组的:
concat,join,slice:slice(start,end),map,filter,some,every
split() join() 的区别
前者是将字符串切割成数组的形式,后者是将数组转换成字符串
js 拷贝
分为深拷贝和浅拷贝。
- 浅拷贝: 只对基本数据类型进行拷贝,方法有:Object.assign() 、es6的结构赋值、数组的slice、concat方法、展开运算符、Array.from。
- 深拷贝:对所有数据类型进行真正的拷贝,方法有:利用JSON.stringify() 和JSON.parse()、利用递归实现。
原型和原型链
- 在JavaScript中万物都是对象,对象和对象之间也有关系,并不是孤立存在的。对象之间的继承关系,在JavaScript中是通过prototype对象指向父类对象,直到指向Object对象为止,这样就形成了一个原型指向的链条,专业术语称之为原型链。
- 原型也是一个对象,通过原型可以实现对象的属性继承,JavaScript的对象中都包含了一个”[[Prototype]]”内部属性,这个属性所对应的就是该对象的原型。
什么是闭包
要了解闭包,要先了解什么是作用域(作用域就是变量与函数的可访问范围: 任何地方都能访问到的对象拥有全局作用域,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部),函数内部可以直接读取全局变量,但是函数外部是无法读取函数内的局部变量,那么如何可以在外部读取到函数内部的变量,可以通过函数内部的函数实现,在这个内部函数中去访问函数内部的变量,并将其返回,这就形成了闭包,即能够读取其他函数内部变量的函数。闭包就是能够读取其他函数内部变量的函数
function test() {
const z = 1
return function() {
console.log('z',z)
}
}
const fn = test()
const z = 2
fn()
// 'z', 1
返回的是函数位置指向最靠近的上一级的z的值
事件循环机制(event loop)
- js代码执行时,先按代码顺序将同步任务压入主执行栈中执行
- 遇到异步任务则先将异步任务压入对应的任务队列中(宏队列或微队列)
- 同步任务执行完毕后,查看微队列,将微任务一一取出进入主执行栈中执行
- 微任务队列清空后,再查看宏队列,只取出第一个宏任务执行,执行完一个宏任务后,回到第三步的操作 这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)
require和import区别
- import和require都是被模块化使用
- require是运行时调用,所以可以随处引入
- import是编译时调用,必须放在文件开头引入,目前部分浏览器不支持,需要用babel把es6转成es5再执行说
怎么理解js中的内存泄露
定义:程序不需要的内存,由于某些原因其不会返回到操作系统或者可用内存池中。 内存泄露会导致(运行缓慢 ,高延迟,崩溃)的问题
常见的导致内存泄露的原因有:
- 意外的全局变量
- 被遗忘的计时器或回调函数
- 脱离文档的DOM的引用
- 闭包
js延迟加载的方式有哪些?
defer和async、动态创建DOM方式(创建script,插入到DOM中,加载完毕后callBack)、按需异步载入js
- 没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。
- 有 async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。
- 有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。
如何阻止事件冒泡
ie:阻止冒泡ev.cancelBubble = true;非IE ev.stopPropagation();
如何阻止默认事件
(1)return false;(2) ev.preventDefault();
浅谈setTimeout 和 setInterval
- 前者是在一定时间过后将函数添加至执行队列,执行时间=延迟时间+之前函数代码执行时间+执行函数时间。
- 后者是不管前一次是否执行完毕,每隔一定时间重复执行,用于精准执行互相没有影响的重复操作。
Javascript作用链域
作用域链的原理和原型链很类似,如果这个变量在自己的作用域中没有,那么它会寻找父级的,直到最顶层。
注意:JS没有块级作用域,若要形成块级作用域,可通过(function(){})();立即执行的形式实现。
Ajax使用
全称 : Asynchronous Javascript And XML
所谓异步,就是向服务器发送请求的时候,我们不必等待结果,而是可以同时做其他的事情,等到有了结果它自己会根据设定进行后续操作,与此同时,页面是不会发生整页刷新的,提高了用户体验。
创建Ajax的过程:
- 创建XMLHttpRequest对象(异步调用对象)
var xhr = new XMLHttpRequest();
- 创建新的Http请求(方法、URL、是否异步)
xhr.open(‘get’,’example.php’,false);
- 设置响应HTTP请求状态变化的函数。
onreadystatechange事件中readyState属性等于4。响应的HTTP状态为200(OK)或者304(Not Modified)。- 发送http请求
xhr.send(data);
- 获取异步调用返回的数据
注意:
1 页面初次加载时,尽量在web服务器一次性输出所有相关的数据,只在页面加载完成之后,用户进行操作时采用ajax进行交互。
2 同步ajax在IE上会产生页面假死的问题。所以建议采用异步ajax。
3 尽量减少ajax请求次数
4 ajax安全问题,对于敏感数据在服务器端处理,避免在客户端处理过滤。对于关键业务逻辑代码也必须放在服务器端处理。
谈谈this的理解
- this总是指向函数的直接调用者(而非间接调用者)
- 如果有new关键字,this指向new出来的那个对象
- 在事件中,this指向目标元素,特殊的是IE的attachEvent中的this总是指向全局对象window。
什么是window对象? 什么是document对象?
window对象代表浏览器中打开的一个窗口。document对象代表整个html文档。实际上,document对象是window对象的一个属性。
null,undefined的区别?
null表示一个对象被定义了,但存放了空指针,转换为数值时为0。
undefined表示声明的变量未初始化,转换为数值时为NAN。
typeof(null) -- object;
typeof(undefined) -- undefined
new操作符具体干了什么呢?
- 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
- 属性和方法被加入到 this 引用的对象中。
- 新创建的对象由 this 所引用,并且最后隐式的返回 this 。
同步和异步的区别?
同步的概念在操作系统中:不同进程协同完成某项工作而先后次序调整(通过阻塞、唤醒等方式),同步强调的是顺序性,谁先谁后。异步不存在顺序性。
- 同步:浏览器访问服务器,用户看到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容之后进行下一步操作。
- 异步:浏览器访问服务器请求,用户正常操作,浏览器在后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容。
回流与重绘
当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树。完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘
DOM操作
- 创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点- 添加、移除、替换、插入
appendChild()
removeChild()
replaceChild()
insertBefore() //在已有的子节点前插入一个新的子节点- 查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)
getElementById() //通过元素Id,唯一性
数组对象有哪些原生方法,列举一下
pop、push、shift、unshift、splice、reverse、sort、concat、join、slice、toString、indexOf、lastIndexOf、reduce、reduceRight、forEach、map、filter、every、some
哪些操作会造成内存泄漏
全局变量、闭包、DOM清空或删除时,事件未清除、子元素存在引用
请描述一下cookie,sessionStorage和localStorage的区别
- localStorage长期存储数据,浏览器关闭数据后不丢失;
- sessionStorage数据在浏览器关闭后自动删除;
- cookie是网站为了标识用户身份而存储在用户本地终端(Client Side)上的数据(通常经过加密)。cookie始终在同源的http请求中携带(即使不需要)都会在浏览器和服务器端间来回传递。session storage和local storage不会自动把数据发给服务器,仅在本地保存;
- 存储大小:cookie数据大小不会超过4K,session storage和local storage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或者更多;
- 有期时间:local storage存储持久数据,浏览器关闭后数据不丢失,除非自动删除数据。session storage数据在当前浏览器窗口关闭后自动删除。cookie 设置的cookie过期时间之前一直有效,即使窗口或者浏览器关闭;
http状态码有那些?分别代表是什么意思?列举2-3个熟悉的状态码
当用户在浏览网页的时候,浏览器会返回一个htttp状态码,主要是用来响应浏览器的请求。
- 200 OK 请求正常处理完毕
- 204 No Content 请求成功处理,没有实体的主体返回
- 301 Moved Permanently 永久重定向,资源已永久分配新URI
- 302 Found 临时重定向,资源已临时分配新URI
- 400 Bad Request 请求报文语法错误或参数错误
- 401 Unauthorized 要通过HTTP认证,或认证失败
- 403 Forbidden 请求资源被拒绝
- 404 Not Found 无法找到请求资源(服务器无理由拒绝)
- 500 Internal Server Error 服务器故障或Web应用故障
- 503 Service Unavailable 服务器超负载或停机维护你可以关闭;
一个 http 请求由什么组成?
请求的方法:post,get
正在请求的URL:请求的地址
请求头:客户端环境信息,身份验证信息
请求体:表单信息等
http协议的 三次握手/四次挥手,可以描述一下吗?
http的三次握手和四次挥手:
浏览器在给服,务器传输数据之前,有三次握手,握手成功之后,才可以传输数据
- 浏览器需要先发送SYN码,客户端请求和服务器建立连接;
- 服务器接收到SYN码,再发送给客户端SYN+ACK码,我可以建立连接;
- 客户端接收到ACK码,验证这个ACK是否正确,如果正确则客户端和服务端则建立起数据连接;双方的数据发送通道都将开启;
四次挥手:
- 当客户端无数据要传输了,会发送FIN码告诉服务器,我发送完毕了;
- 当服务器接收完毕后,告诉客户端ACK码,告诉客户端你可以把数据通道关闭了;
- 当服务器发送完毕之后,也会发送FIN码,告诉浏览器,数据发送完毕;
- 当客户端接收完毕 之后,同样发送ACK码,告诉服务器,数据接收 完毕,
ajax请求的时候get 和post方式的区别?
1.使用Get请求时,参数在URL中显示,而使用Post方式,则不会显示出来
2.使用Get请求发送数据量小,Post请求发送数据量大
什么是防抖和节流?有什么区别?如何实现?
防抖:
触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间
- 举个栗子
每次触发事件时都取消之前的延时调用方法
function debounce(fn) {
let timeout = null; // 创建一个标记用来存放定时器的返回值
return function () {
clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
fn.apply(this, arguments);
}, 500);
};
}
function sayHi() {
console.log('防抖成功');
}
var inp = document.getElementById('inp');
inp.addEventListener('input', debounce(sayHi)); // 防抖
节流:
高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率
- 举个栗子
每次触发事件时都判断当前是否有等待执行的延时函数
function throttle(fn) {
let canRun = true; // 通过闭包保存一个标记
return function () {
if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return
canRun = false; // 立即设置为false
setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
fn.apply(this, arguments);
// 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
canRun = true;
}, 500);
};
}
function sayHi(e) {
console.log(e.target.innerWidth, e.target.innerHeight);
}
window.addEventListener('resize', throttle(sayHi));
持续更新中......