1. JS 有哪些数据类型?

依据 JavaScript 中的变量类型传递形式,分为根本数据类型援用数据类型两大类七种。
根本数据类型包含UndefinedNullBooleanNumberStringSymbol (ES6新增)六种
援用数据类型只有Object一种,次要包含对象、数组和函数。
判断数据类型采纳typeof操作符,有两种语法:

typeof 123;//语法一const FG = 123;typeof FG;//语法二typeof(null) //返回 object;null == undefined //返回true,因为undefined派生自null;null === undefined //返回false。

2. 根本数据类型和援用数据类型有什么区别?

(1)两者作为函数的参数进行传递时:

    根本数据类型**传入的是数据的正本**,原数据的更改不会影响传入后的数据。      援用数据类型**传入的是数据的援用地址**,原数据的更改会影响传入后的数据。  

(2)两者在内存中的存储地位:

    根本数据类型**存储在栈中**。      援用数据类型在**栈中存储了指针**,该指针指向的**数据实体存储在堆中**。  

3. 判断数据类型的办法有哪些?

(1)利用typeof能够判断数据的类型;
(2)A instanceof B能够用来判断A是否为B的实例,但它不能检测 null 和 undefined
(3)B.constructor == A能够判断A是否为B的原型,但constructor检测 Object与instanceof不一样,还能够解决根本数据类型的检测

不过函数的 constructor 是不稳固的,这个次要体现在把类的原型进行重写,在重写的过程中很有可能呈现把之前的constructor给笼罩了,这样检测进去的后果就是不精确的。

(4)Object.prototype.toString.call()

Object.prototype.toString.call() 是最精确最罕用的形式。

4. 与深拷贝有何区别?如何实现?

浅拷贝只复制指向某个对象的指针,而不复制对象自身。浅拷贝的实现形式有:
(1)Object.assign():需注意的是指标对象只有一层的时候,是深拷贝;
(2)扩大运算符;
深拷贝就是在拷贝数据的时候,将数据的所有援用构造都拷贝一份。深拷贝的实现形式有:
(1)手写遍历递归赋值;
(2)联合应用JSON.parse()JSON.stringify()办法。

5. let、const的区别是什么?

varletconst都是用于申明变量或函数的关键字。其区别在于:

varletconst
作用域函数作用域块级作用域块级作用域
作用域内申明晋升无(暂时性死区)
是否可反复申明
是否可反复赋值否(常量)
初始化时是否必须赋值

6. 什么是执行上下文和执行栈?

变量或函数的执行上下文,决定了它们的行为以及能够拜访哪些数据。每个上下文都有一个关联的变量对象,而这个上下文中定义的所有变量和函数都存在于这个对象上(如DOM中全局上下文关联的便是window对象)。
每个函数调用都有本人的上下文。当代码执行流进入函数时,函数的上下文被推到一个执行栈中。在函数执行完之后,执行栈会弹出该函数上下文,在其上的所有变量和函数都会被销毁,并将控制权返还给之前的执行上下文。 JS的执行流就是通过这个执行栈进行管制的

7. 什么是作用域和作用域链?

作用域能够了解为一个独立的地盘,能够了解为标识符所能失效的范畴。作用域最大的用途就是隔离变量,不同作用域下同名变量不会有抵触。ES6中有全局作用域、函数作用域和块级作用域三层概念。
当一个变量在以后块级作用域中未被定义时,会向父级作用域(创立该函数的那个父级作用域)寻找。如果父级仍未找到,就会再一层一层向上寻找,直到找到全局作用域为止。这种一层一层的关系,就是作用域链

8. 作用域和执行上下文的区别是什么?

(1)函数的执行上下文只在函数被调用时生成,而其作用域在创立时曾经生成;
(2)函数的作用域会蕴含若干个执行上下文(有可能是零个,当函数未被调用时)。

9. this指向的各种状况都有什么?

this的指向只有在调用时能力被确定,因为this是执行上下文的一部分。
(1)全局作用域中的函数:其外部this指向window

var a = 1;function fn(){  console.log(this.a)}fn() //输入1

(2)对象外部的函数:其外部this指向对象自身:

var a = 1;var obj = {  a:2,  fn:function(){      console.log(this.a)    }}obj.fn() //输入2

(3)构造函数:其外部this指向生成的实例:

function createP(name,age){    this.name = name //this.name指向P  this.age = age //this.age指向P}var p = new createP("老李",46)

(4)由applycallbind革新的函数:其this指向第一个参数:

function add(c,d){    return this.a + this.b + c + d}var o = {a:1,b:2)add.call(o,5,7) //输入15

(5)箭头函数:箭头函数没有本人的this,看其外层的是否有函数,如果有,外层函数的this就是外部箭头函数的this,如果没有,则thiswindow

参考 前端进阶面试题具体解答

10.如何扭转this指针的指向?

能够应用applycallbind办法扭转this指向(并不会扭转函数的作用域)。比拟如下:
(1)三者第一个参数都是this要指向的对象,也就是想指定的上下文,上下文就是指调用函数的那个对象(没有就指向全局window);
(2)apply的第二个参数是数组或者类数组对象,bindcall接管多个参数并用逗号隔开;
(3)applycall只对原函数做改变,bind会返回新的函数(要失效还得再调用一次)。

    console.log(Math.max.apply(null, [1,2,3])) //--apply 输入3    console.log(Math.max.apply(null, new Array(1,2,3))) //--apply 输入3    console.log(Math.max.call(null, 1,2,3)) //--call 输入3    console.log(Math.max.bind(null, 1,2,3)()) //--bind 输入3

11.什么是闭包?

闭包就是援用了其余函数作用域中变量的函数,这种模式通常在函数嵌套构造中实现。外面的函数能够拜访里面函数的变量,里面的变量的是这个外部函数的一部分。闭包有如下作用:
(1)增强封装,模仿实现公有变量;
(2)实现常驻内存的变量。

闭包不能滥用,否则会导致内存泄露,影响网页的性能。闭包应用完了后,要立刻开释资源,将援用变量指向null

12. 什么是原型、原型链?

原型:JS申明构造函数(用来实例化对象的函数)时,会在内存中创立一个对应的对象,这个对象就是原函数的原型构造函数默认有一个prototype属性prototype的值指向函数的原型。同时原型中也有一个constructor属性constructor的值指向原函数
通过构造函数实例化进去的对象,并不具备prototype属性,其默认有一个__proto__属性__proto__的值指向构造函数的原型对象。在原型对象上增加或批改的属性,在所有实例化出的对象上都可共享。

当在实例化的对象中拜访一个属性时,首先会在该对象外部寻找,如找不到,则会向其__proto__指向的原型中寻找,如仍找不到,则持续向原型中__proto__指向的下级原型中寻找,直至找到或Object.prototype为止,这种链状过程即为原型链

13. 何为防抖和节流?如何实现?

防抖和节流都是避免短时间内高频触发事件的计划。
防抖的原理是:如果肯定工夫内屡次执行了某事件,则只执行其中的最初一次。
节流的原理是:要执行的事件每隔一段时间会被冷却,无奈执行。
利用场景有:搜寻框实时搜寻,滚动扭转相干的事件。

//@fn: 要执行的函数//@delay: 设定的时限//防抖函数function debunce(fn,delay){    let flag = null;  return function(){      if(flag) clearTimeout(flag)    //利用apply扭转函数指向,使得封装后的函数能够接管event自身    flag = setTimeout(()=>fn.apply(this,arguments),delay)  }}//节流函数function throttle(fn,delay){    let flag = true;  return function(){      if(!flag) return false;    flag = false;    setTimeout(()=>{      fn.apply(this,arguments)      flag=true    },delay)  }}

14. 如何了解同步和异步?

同步:依照代码书写程序一一执行解决指令的一种模式,上一段代码执行完能力执行下一段代码。
异步:能够了解为一种并行处理的形式,不用期待一个程序执行完,能够执行其它的工作。

JS之所以须要异步的起因在于JS是单线程运行的。罕用的异步场景有:定时器、ajax申请、事件绑定

15. JS是如何实现异步的?

JS引擎是单线程的,但又能实现异步的起因在于事件循环和工作队列体系。
事件循环:
JS 会创立一个相似于 while (true) 的循环,每执行一次循环体的过程称之为 Tick。每次 Tick 的过程就是查看是否有待处理事件,如果有则取出相干事件及回调函数放入执行栈中由主线程执行。待处理的事件会存储在一个工作队列中,也就是每次 Tick 会查看工作队列中是否有须要执行的工作。
工作队列:
异步操作会将相干回调增加到工作队列中。而不同的异步操作增加到工作队列的机会也不同,如 onclick, setTimeout, ajax 解决的形式都不同,这些异步操作是由浏览器内核的 webcore 来执行的,浏览器内核蕴含3种 webAPI,别离是 DOM Bindingnetworktimer模块。
onclickDOM Binding 模块来解决,当事件触发的时候,回调函数会立刻增加到工作队列中。 setTimeouttimer 模块来进行延时解决,当工夫达到的时候,才会将回调函数增加到工作队列中。 ajaxnetwork 模块来解决,在网络申请实现返回之后,才将回调增加到工作队列中。
主线程:
JS 只有一个线程,称之为主线程。而事件循环是主线程中执行栈里的代码执行结束之后,才开始执行的。所以,主线程中要执行的代码工夫过长,会阻塞事件循环的执行,也就会阻塞异步操作的执行。
只有当主线程中执行栈为空的时候(即同步代码执行完后),才会进行事件循环来察看要执行的事件回调,当事件循环检测到工作队列中有事件就取出相干回调放入执行栈中由主线程执行。

16. 什么是AJAX?如何实现?

ajax是一种可能实现部分网页刷新的技术,能够使网页异步刷新。
ajax的实现次要包含四个步骤:

    (1)创立外围对象`XMLhttpRequest`;      (2)利用`open`办法关上与服务器的连贯;      (3)利用`send`办法发送申请;("POST"申请时,还需额定设置申请头)      (4)监听服务器响应,接管返回值。  
//1-创立外围对象//该对象有兼容问题,低版本浏览器应应用ActiveXObjectconst xthhp = new XMLHttpRequest();//2-连贯服务器//open(method,url,async)xhttp.open("POST","http://localhost:3000",true)//设置申请头xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");//3-发送申请//send办法发送申请参数,如为GET办法,则在open中url后拼接xhttp.send({_id:123})//4-接管服务器响应//onreadystatechange事件,会在xhttp的状态发生变化时主动调用xhttp.onreadystatechange =function(){  //状态码共5种:0-未open  1-已open  2-已send  3-读取响应  4-响应读取完结  if(xhttp.readyState == 4 && xhttp.status == 200){      alert("ajax申请已实现")  }}

17. 实现异步的形式有哪些?

(1)回调函数模式:将须要异步执行的函数作为回调函数执行,其毛病在于解决简单逻辑异步逻辑时,会造成回调天堂(回调嵌套层数太多,代码构造凌乱);
(2)事件监听模式:采纳事件驱动的思维,当某一事件产生时触发执行异步函数,其毛病在于整个代码全副得变为事件驱动模式,难以分辨主流程;
(3)公布订阅模式:当异步工作执行实现时公布音讯给信号核心,其余工作通过在信号核心中订阅音讯来确定本人是否开始执行;
(4)Promise(ES6)Promise对象共有三种状态pending(初始化状态)、fulfilled(胜利状态)、rejected(失败状态)。
(5)async/await(ES7):基于Promise实现的异步函数;
(6)利用生成器实现。

18. 怎么了解Promise对象?

Promise对象有如下两个特点
(1)对象的状态不受外界影响Promise对象共有三种状态pendingfulfilledrejected。状态值只会被异步后果决定,其余任何操作无奈扭转。
(2)状态一旦成型,就不会再变,且任何时候都可失去这个后果。状态值会由pending变为fulfilledrejected,这时即为resolved

Promise的毛病有如下三个毛病:
(1)Promise一旦执行便无奈被勾销;
(2)不可设置回调函数,其外部产生的谬误无奈捕捉;
(3)当处于pending状态时,无奈得悉其具体倒退到了哪个阶段。

Pomise中罕用的办法有:
(1)Promise.prototype.then()Promise实例的状态产生扭转时,会调用then外部的回调函数。then办法承受两个参数(第一个为resolved状态时时执行的回调,第一个为rejected状态时时执行的回调)
(2)Promise.prototype.catch().then(null, rejection).then(undefined, rejection)的别名,用于指定产生谬误时的回调函数。

19. 怎么了解宏工作,微工作???

宏工作有:script(整体代码)setTimeoutsetIntervalI/O、页面渲染;
微工作有:Promise.thenObject.observeMutationObserver
执行程序大抵如下:
主线程工作——>宏工作——>微工作——>微工作里的宏工作——>.......——>直到工作全副实现

20. 什么是跨域?怎么解决跨域问题?

跨域问题理论是由同源策略衍生出的一个问题,当传输协定、域名、端口任一部分不统一时,便会产生跨域问题,从而拒绝请求,但<img src=XXX> <link href=XXX><script src=XXX>;人造容许跨域加载资源。解决方案有:
(1)JSONP
原理:利用<script>;标签没有跨域限度的破绽,使得网页能够失去从其余起源动静产生的JSON数据(前提是服务器反对)。
长处:实现简略,兼容性好。
毛病:仅反对get办法,容易受到XSS攻打。
(2)CORS
原理:服务器端设置Access-Control-Allow-Origin以开启CORS。该属性示意哪些域名能够拜访资源,如设置通配符则示意所有网站均可拜访。
实现实例(express):

//app.js中设置var app = express();//CORS跨域-------------------------------------------------------------------------------------// CORS:设置容许跨域中间件var allowCrossDomain = function (req, res, next) {  // 设置容许跨域拜访的 URL(* 示意容许任意 URL 拜访)  res.header("Access-Control-Allow-Origin", "*");  // 设置容许跨域拜访的申请头  res.header("Access-Control-Allow-Headers", "X-Requested-With,Origin,Content-Type,Accept,Authorization");  // 设置容许跨域拜访的申请类型  res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");  // 设置容许服务器接管 cookie  res.header('Access-Control-Allow-Credentials', 'true');  next();};app.use(allowCrossDomain);//------------------------------------------------------------------------------------

(3)Node中间件代理
原理:同源策略仅是浏览器须要遵循的策略,故搭建中间件服务器转发申请与响应,达到跨域目标。

/* server1.js 代理服务器(http://localhost:3000)*/const http = require('http')// 第一步:承受客户端申请const server = http.createServer((request, response) => {// 代理服务器,间接和浏览器间接交互,须要设置CORS 的首部字段  response.writeHead(200,{           'Access-Control-Allow-Origin':'*',       'Access-Control-Allow-Methods':'*',        'Access-Control-Allow-Headers':'Content-Type'      })// 第二步:将申请转发给服务器    const proxyRequest = http.request({        host:'127.0.0.1',        port:4000,        url:'/',        method:request.method,        headers:request.headers          },  serverResponse =>{   // 第三步:收到服务器的响应        var body = ''        serverResponse.on('data', chunk =>{          body += chunk                        })        serverResponse.on('end',()=> {          console.log('The data is '+ body)// 第四步:将响应后果转发给浏览器          response.end(body)                      })         })  .end()  })server.listen(3000,()=>{console.log('中间件服务器地址: http://localhost:3000')})// server2.js(http://localhost:4000)const http = require("http");const data = { title: "fontend", password: "123456" };const server = http.createServer((request, response) => {    if (request.url === "/") {        response.end(JSON.stringify(data));    }});server.listen(4000, () => {    console.log("The server is running at http://localhost:4000");});

(4)nginx反向代理
原理:相似Node中间件服务器,通过nginx代理服务器实现。
实现办法:下载安装nginx,批改配置。

21. 实现继承的办法有哪些???

实现继承的办法有:
(1)class+extends继承(ES6)

//类模板class Animal {  constructor(name){    this.name = name  }}//继承类class Cat extends Animal{//重点。extends办法,外部用constructor+super  constructor(name) {    super(name);    //super作为函数调用时,代表父类的构造函数  }//constructor可省略  eat(){    console.log("eating")  }}

(2)原型继承

//类模板function Animal(name) {  this.name = name; }//增加原型办法Animal.prototype.eat = function(){  console.log("eating")}function Cat(furColor){    this.color = color ;};//继承类Cat.prototype = new Animal()//重点:子实例的原型等于父类的实例

(3)借用构造函数继承

function Animal(name){    this.name = name}function Cat(){    Animal.call(this,"CatName")//重点,调用父类的call办法}

(4)寄生组合式继承(重点)

22. DOM事件模型和事件流?

DOM事件模型包含事件捕捉(自上而下触发)与事件冒泡(自下而上触发,ie用的就是冒泡)机制。基于事件冒泡机制能够实现事件代理

事件捕捉 事件冒泡

DOM事件流包含三个阶段事件捕捉阶段、处于指标阶段、事件冒泡阶段。

23. EventLoop事件循环是什么?

js是一门单线程的须要,它的异步操作都是通过事件循环来实现的。整个事件循环大体由执行栈、音讯队列和微工作队列三个局部组成。
同步代码会间接在执行栈中调用执行。
定时器中的回调会在执行栈被清空且定时达成时推入执行栈中执行。
promiseasync异步函数的回调会被推入到微工作队列中,当执行栈被清空且异步操作实现时立刻执行。

24. require/import之间的区别?

(1)require是CommonJS语法,import是ES6语法;
(2)require只在后端服务器反对,import在高版本浏览器及Node中都能够反对;
(3)require引入的是原始导出值的复制,import则是导出值的援用;
(4)require时运行时动静加载,import是动态编译;
(5)require调用时默认不是严格模式,import则默认调用严格模式.

前端面试指南系列传送门:

前端面试指南之Vue面试题总结

前端面试指南之HTML面试题总结

前端面试指南之CSS面试题总结