2019前端面试题

1.什么是面向对象?什么是面向过程?javascript

1)面向对象的重点是对象。当解决一个问题的时候,面向对象会把事物抽象成对象,也就是说这个问题包含哪些对象,而后给这些对象赋一些属性和方法,让每一个对象执行本身的方法,问题获得解决。css

2)面向过程的重点是过程。解决一个问题的时候,面向过程会把问题拆分红一个个的函数和数据(方法的参数)。而后按照必定的顺序执行这些方法,执行完这些方法,问题获得解决。html

 

2.什么是面向对象程序设计?前端

答:将计算机须要处理的问题都抽象成对象,在抽象成类,帮助人们实现对现实世界的抽象与数字建模。vue

面向对象的程序设计更加符合人的思考逻辑和对事物的处理。html5

 

3.什么是对象?什么是类?java

答:对象是由类实例化出来的,类的实例称为对象。程序员

类是具备相同特征和功能的对象的抽象。es6

类和对象的关系就比如模具和铸件的关系,类的实例化结果就是对象,而对象的抽象就是类。web

 

4.什么是继承?

在面向对象的编程中,当两个类具备相同的特征(属性)和行为(方法)时,能够将相同的部分抽取出来放到一个类中做为父类,其余两个类继承这个父类。继承后的子类自动拥有了父类的部分属性和方法。

经过继承建立的新类被称为“子类”或“派生类”

被继承的类称为“基类”、“父类”或“超类”

好比:

狗{吠;}牧羊犬 继承 狗{放羊;}上面的例子中,狗类是父类,牧羊犬类是子类。牧羊犬类经过继承得到狗类的吠的能力,同时增长了本身独有的放羊的能力。

 

JS中的继承主要是经过原型链实现的

每一个构造函数(constructor)都有一个原型对象(prototype),原型对象都包含一个指向构造函数的指针,而实例(instance)都包含一个指向原型对象的内部指针

若是试图引用对象(实例instance)的某个属性,会首先在对象内部寻找该属性,直至找不到,而后才在该对象的原型(instance.prototype)里去找这个属性

http://www.javashuo.com/article/p-zugxclij-h.html

 

5.谈谈你对前端性能优化的理解

1)请求数量,合并脚本和样式表,拆分初始化负载

2)请求带宽,精简JavaScript,移除重复脚本,图像优化,将icon作成字体

3)页面结构:将样式表放在顶部,将脚本放在底部,尽早刷新文档的输出

 

6.为何使用框架?使用框架的优点?

1)重复应用的外部JS:使用框架后咱们能够把这些文件写在入口文件中,一劳永逸

2)组件化:组件是前端框架里很是强大的功能之一,它能够扩展你的HTML,封装能够重用的代码块,好比你的轮播图、tab切换、页面头部、页面底部等等。

3)开发周期长:jQuery开发时,须要频繁的操做DOM,几乎任何动态效果都须要去选择DOM来进行相应的操做,这使开发变得麻烦起来,不少的时间都用到了操做DOM上,项目的开发周期天然被延长。

使用框架开发,框架中封装许多的频繁使用的功能,例如Angular中的指令,指令功能有数据绑定,表单验证,数据格式化等等。这时前端的重点只须要放在数据逻辑部分,而不须要花费很大的精力去操做DOM完成功能,从而加快项目进度。

4)性能:不少DOM操做会引发回流和重绘,对于jQuery来讲,大量的操做DOM虽然方便,可是很浪费页面性能。

框架和jQuery虽然都会操做DOM,可是框架把大量的DOM进行了处理和优化(例如Vue的虚拟DOM),经过数据驱动,就能渲染出DOM,大大提高了性能。

 

7.盒模型包含什么?

答:padding 、 margin 、 content 、 border

 

8.谈谈cookie的弊端?

1)每一个特定域名下生成的cookie数量有限

2)cookie的最大大约为4096字节,为了兼容性,通常不能超过4095字节

3)安全性问题。若是cookie被人拦截了,就能够取得全部的session信息

 

9.浏览器本地存储?

答:在HTML5中提供了sessionStorage和localStorage。

sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问而且当会话结束后数据也随之销毁,是会话级别的存储。

localStorage用于持久化的本地存储,除非主动删除数据,不然数据是永远不会过时的。

 

10.web storage和cookie的区别

a. Cookie的大小是受限的

b. 每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽

c. cookie还须要指定做用域,不能够跨域调用

d. Web Storage拥有setItem,getItem等方法,cookie须要前端开发者本身封装setCookie,getCookie

e. Cookie的做用是与服务器进行交互,做为HTTP规范的一部分而存在 ,而Web Storage仅仅是为了在本地“存储”数据而生

f. IE七、IE6中的UserData经过简单的代码封装能够统一到全部的浏览器都支持web storage

 

11.线程与进程的区别

根本区别:进程是操做系统资源分配的基本单位,而线程是任务调度和执行的基本单位

http://www.javashuo.com/article/p-wwzriyfh-gp.html

 

12.什么叫优雅降级和渐进加强?

渐进加强 progressive enhancement:

针对低版本浏览器进行构建页面,保证最基本的功能,而后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。

优雅降级 graceful degradation:

一开始就构建完整的功能,而后再针对低版本浏览器进行兼容。

区别:

a. 优雅降级是从复杂的现状开始,并试图减小用户体验的供给

b. 渐进加强则是从一个很是基础的,可以起做用的版本开始,并不断扩充,以适应将来环境的须要

c. 降级(功能衰减)意味着往回看;而渐进加强则意味着朝前看,同时保证其根基处于安全地带

 

13.web socket

要作长链接的话,是不能用http协议来作的,由于http协议已是应用层协议了,而且http协议是无状态的,而咱们要作长链接,确定是须要在应用层封装本身的业务,因此就须要基于TCP协议来作,而基于TCP协议的话,就要用到Socket了

  • Socket是java针对tcp层通讯封装的一套网络方案
  • TCP协议咱们知道,是基于ip(或者域名)和端口对指定机器进行的点对点访问,他的链接成功有两个条件,就是对方ip能够到达和端口是开放的
  • Socket能完成TCP三次握手,而应用层的头部信息须要本身去解析,也就是说,本身要制定好协议,而且要去解析byte

14.HTTP 与 TCP/IP 的区别?

TCP是传输层协议,定义数据传输和链接方式的规范。握手过程当中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。

HTTP 超文本传送协议(Hypertext Transfer Protocol )是应用层协议,定义的是传输数据的内容的规范。

HTTP协议中的数据是利用TCP协议传输的,特色是客户端发送的每次请求都须要服务器回送响应,它是TCP协议族中的一种,默认使用 TCP 80端口。

比如网络是路,TCP是跑在路上的车,HTTP是车上的人。每一个网站内容不同,就像车上的每一个人有不一样的故事同样。

关于TCP/IP和HTTP协议的关系,网络有一段比较容易理解的介绍:“咱们在传输数据时,能够只使用(传输层)TCP/IP协议,可是那样的话,若是没有应用层,便没法识别数据内容,若是想要使传输的数据有意义,则必须使用到应用层协议,应用层协议有不少,好比HTTP、FTP、TELNET等,也能够本身定义应用层协议。WEB使用HTTP协议做应用层协议,以封装HTTP 文本信息,而后使用TCP/IP作传输层协议将它发到网络上。”

http://www.javashuo.com/article/p-qvsvllmo-gp.html

 

15.为何说HTTP链接是无状态的?

答:客户端和服务器在某次会话产生的数据,这些数据不会被保留。

 

16.什么是websocket?

WebSocket 是 HTML5 开始提供的一种在单个 TCP 链接上进行全双工通信的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,容许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只须要完成一次握手,二者之间就直接能够建立持久性的链接,并进行双向数据传输。

在 WebSocket API 中,浏览器和服务器只须要作一个握手的动做,而后,浏览器和服务器之间就造成了一条快速通道。二者之间就直接能够数据互相传送。

http://www.javashuo.com/article/p-uokgcivn-go.html

 

17.网络七层协议(OSI)是哪些?

答:1.物理层   2.数据链路层  3.网络层  4.传输层  5.会话层  6.表示层  7.应用层

 

18.什么是同源策略?

答:同源策略指的是协议、域名、端口相同,是一种安全协议

指一段脚本只能读取来自同一窗口的文档和属性

 

19.AMD、CMD、CommonJS 和 ES6 的对比

https://blog.csdn.net/tangxiujiang/article/details/81104174

 

20.浏览器的内核分别是什么?

IE浏览器的内核Trident;

Mozilla的Gecko;

Chrome的Blink(WebKit的分支);

Opera内核原为Presto,现为Blink;

 

21.前端页面有哪三层构成,分别是什么?做用是什么?

a. 结构层:由 HTML 或 XHTML 之类的标记语言负责建立,仅负责语义的表达。解决了页面“内容是什么”的问题。

b. 表示层:由CSS负责建立,解决了页面“如何显示内容”的问题。

c. 行为层:由脚本负责。解决了页面上“内容应该如何对事件做出反应”的问题。

 

23.谈谈vue中的MVVM模式?

答:MVVM全称是Model-View-ViewModel

Vue是以数据为驱动的,Vue自身将DOM和数据进行绑定,一旦建立绑定,DOM和数据将保持同步,每当数据发生变化,DOM会跟着变化。

ViewModel是Vue的核心,它是Vue的一个实例。Vue实例时做用域的这个HTML元素能够是body,也能够是某个id所指代的元素。

DOMListenersDataBindings是实现双向绑定的关键。

DOMListeners监听页面全部View层DOM元素的变化,当发生变化,Model层的数据随之变化;

DataBindings监听Model层的数据,当数据发生变化,View层的DOM元素随之变化。

MVVM框架提倡把渲染和逻辑分离。简单来讲就是不要再让 JS 直接操控 DOMJS 只须要管理状态便可,而后再经过一种模板语法来描述状态和界面结构的关系。

 

24.v-showv-if指令的共同点和不一样点?

  • v-show指令是经过修改元素的displayCSS属性让其显示或者隐藏
  • v-if指令是直接销毁和重建DOM达到让元素显示和隐藏的效果

25.keep-alive

keep-alive是Vue提供的一个抽象组件,用来对组件进行缓存,从而节省性能,因为是一个抽象组件,因此在vue页面渲染完毕后不会被渲染成一个DOM元素

https://www.jianshu.com/p/4b55d312d297

 

26.Vue生命周期

1)beforeCreate:

完成实例初始化,初始化非响应式变量;

this指向建立的实例;

能够加载loading事件;

data computed watch methods 上的方法和数据均不能访问;

2)created:

实例建立完成;

完成数据(data props computed)的初始化,导入依赖项;

可访问data computed watch methods上的数据和方法;

未挂载DOM,不能访问$el,$ref为空;

可在这结束loading,还能作一些初始化,实现函数自执行;

能够对data数据进行操做,可进行一些请求,请求不易过多,避免白屏时间太长;

若在此阶段进行的 DOM 操做必定要放在 Vue.nextTick() 的回调函数中

3)beforeMount:

有了el,编译了template/outerHTML;

能找到对应的template,并编译成render函数;

4)mounted:

完成建立vm.$el,和双向绑定;

完成挂载DOM 和渲染;可在mounted钩子对挂载的dom进行操做;

即有了DOM 且完成了双向绑定,可访问DOM节点,$ref;

可在这发起后端请求,拿回数据,配合路由钩子作一些事情;

可对DOM 进行操做;

5)beforeUpdate:

数据更新以前;

可在更新前访问现有的DOM,如手动移除添加的事件监听器;

6)updated:

完成虚拟DOM的从新渲染和打补丁;

组件DOM 已完成更新;

可执行依赖的dom 操做;

注意:不要在此函数中操做数据,会陷入死循环的。

7)activated:

在使用vue-router时有时须要使用<keep-alive></keep-alive>来缓存组件状态,这个时候created钩子就不会被重复调用了
若是咱们的子组件须要在每次加载的时候进行某些操做,可使用activated钩子触发

8)deactivated:

keep-alive 组件被移除时使用

9)beforeDestory:

在执行app.$destroy()以前

可作一些删除提示,如:你确认删除XX吗? 

可用于销毁定时器,解绑全局时间 销毁插件对象

10)destroyed:

当前组件已被删除,销毁监听事件 组件 事件 子实例也被销毁

这时组件已经没有了,你没法操做里面的任何东西了

http://www.javashuo.com/article/p-mzpconrz-ge.html

 

27.父子组件的生命周期?

仅当子组件完成挂载后,父组件才会挂载

当子组件完成挂载后,父组件会主动执行一次beforeUpdate/updated钩子函数(仅首次)

父子组件在data变化中是分别监控的,可是在更新props中的数据是关联的(可实践)

销毁父组件时,先将子组件销毁后才会销毁父组件

 

兄弟组件的初始化(mounted以前)分开进行,挂载是从上到下依次进行

当没有数据关联时,兄弟组件之间的更新和销毁是互不关联的

 

28.什么是Vue的生命周期?

Vue实例从建立到销毁的过程,就是生命周期。

 

29.Vue生命周期的做用是什么?

Vue生命周期有不少事件钩子,让咱们在控制整个Vue实例的过程更容易造成好的逻辑。

 

30.Vue生命周期总共有几个阶段?
答:它能够总共分为8个阶段:建立前/后, 载入前/后,更新前/后,销毁前/销毁后。

 

31.Vue双向绑定的原理是什么?

Vue采用的是数据劫持结合发布和-订阅者模式的方式,经过Object.defineProperty()来劫持各个属性的setter,getter,在数据变更时发布消息给订阅者,触发相应的监听回调

http://www.javashuo.com/article/p-pvlyorwx-hu.html

 

32.Vue组件之间的参数传递?

1.父组件与子组件传值

父组件传给子组件:子组件经过props方法接受数据;

子组件传给父组件:$emit方法传递参数

2.非父子组件间的数据传递,兄弟组件传值

eventBus,就是建立一个事件中心,至关于中转站,能够用它来传递事件和接收事件。项目比较小时,用这个比较合适。

(虽然也有很多人推荐直接用VUEX,具体来讲看需求咯。技术只是手段,目的达到才是王道。)

 

33.Vuex中有5中默认的基础对象

  • state:存储状态(变量)
  • getters:对数据获取以前的再次编译,能够理解为state的计算属性。咱们在组件中使用 $sotre.getters.fun()
  • mutations:修改状态,而且是同步的。在组件中使用$store.commit('',params)。这个和咱们组件中的自定义事件相似。
  • actions:异步操做。在组件中使用是$store.dispath('')
  • modules:store的子模块,为了开发大型项目,方便状态管理而使用的。这里咱们就不解释了,用起来和上面的同样。

 

34.Vuex是什么?

答:vuex 是一个专门为vue.js应用程序开发的状态管理模式。

这个状态咱们能够理解为在data中的属性,须要共享给其余组件使用的部分。

也就是说,是咱们须要共享的data,使用vuex进行统一集中式的管理。

 

35.Vuex使用

http://www.javashuo.com/article/p-fdwnabwi-go.html

 

36.Vuex中mutation和action的区别

答:mutation 有必须同步执行这个限制,Action 就不受约束!咱们能够在 action 内部执行异步操做

http://www.javashuo.com/article/p-enotvqwo-gn.html

 

37.原型、原型链、constructor

每一个函数都有一个prototype属性,prototype是函数的原型对象。原型对象是用来给实例共享属性和方法的

Javascript中全部的对象都是Object的实例,并继承Object.prototype的属性和方法,也就是说,Object.prototype是全部对象的爸爸

每一个对象都有__proto__属性,这个__proto__指向的是建立这个对象的构造函数的prototype

 

Javascript语言的继承机制一直很难被人理解

它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分,全靠一种很奇特的"原型链"(prototype chain)模式,来实现继承

 

每一个对象都有一个constructor属性,它引用了初始化该对象的构造函数

 

http://www.javashuo.com/article/p-xnxtvxpv-gn.html

http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html

 

38.JS的基本数据类型和引用数据类型以及深拷贝和浅拷贝

基本数据类型:

他们的值在内存中占据着固定大小的空间,并被保存在内存中;

当一个变量向另外一个变量复制基本类型的值,会建立这个值的副本,而且咱们不能给基本数据类型的值添加属性;

Undefined / Null / Boolean / Number / String,它们是直接按值存放的,能够直接访问。

引用数据类型:(对象、函数、数组

复杂的数据类型便是引用类型,它的值是对象,保存在内存中,包含引用类型值的变量实际上包含的不是对象自己,而是一个指向该对象的指针

从一个变量向另外一个变量复制引用类型的值,复制的实际上是指针地址而已,所以两个变量最终都指向同一个对象。

访问引用数据类型的值时,首先从栈中得到该对象的地址指针,而后再从堆内存中取得所需的数据。

 

浅拷贝:是拷贝一层,深层次的对象级别的就拷贝引用;

深拷贝:是拷贝多层,每一级别的数据都会拷贝出来;

 

浅拷贝的时候若是数据是基本数据类型,那么就如同直接赋值那种,会拷贝其自己,若是除了基本数据类型以外还有一层对象,那么对于浅拷贝而言就只能拷贝其引用,对象的改变会反应到拷贝对象上;

可是深拷贝就会拷贝多层,即便是嵌套了对象,也会都拷贝出来。

 

当咱们使用对象拷贝时,若是属性是对象或数组时,这时咱们传递的只是一个地址。所以子对象在访问该属性时,会根据地址回溯到父对象指向的堆内存中,即父子对象发生了关联,二者的属性值会指向同一内存空间。

 

看一个比较经典的面试题:

var a = function() {console.log(11)};
 
var b = function() {console.log(11)};
 
console.log( a==b ); //false
 
 
console.log( {}=={} ); //false
 
console.log( []==[] ); //false

为何结果都是false?

变量 a 实际保存的是指向堆内存中对象的一个指针,而 b 保存的是指向堆内存中另外一个对象的一个指针;

虽然这两个对象的值是同样的,但它们是独立的2个对象,占了2分内存空间;因此 a == b 为 false

 

var a = {}; 

var b = a;
console.log( a
== b ); // true

这时变量 b 复制了变量 a 保存的指针,它们都指向堆内存中同一个对象;因此 a == b 为 true

 

传值与传址:

基本类型与引用类型最大的区别实际就是 传值 与 传址 的区别

var a = [1,2,3,4,5];
 
var b = a;
 
var c = a[0];
 
console.log(b); // [1,2,3,4,5]
 
console.log(c); // 1
 
 
b[4] = 6;
 
c = 7;
 
console.log(a[4]); //6
 
console.log(a[0]); //1

从上面代码能够得知,当改变b中的数据时,a也发生了变化;可是当咱们改变c的数值时,a却没有发生改变

这就是传值与传址的区别。由于a是数组,属于引用类型,因此a给b传的是栈中的地址,而不是堆内存中的对象。

而c仅仅是从a堆内存中获取的一个数值,并保存在栈中。因此b修改的时候,会根据地址回到a堆内存中修改;c则直接在栈中修改,而且不能指向a堆内存中。

 

https://blog.csdn.net/Bruce__taotao/article/details/82690506

https://www.cnblogs.com/c2016c/articles/9328725.html

https://blog.csdn.net/weixin_37719279/article/details/81240658

 

39.什么是递归?

https://pushy.site/2018/02/20/recursion/

 

40.什么是闭包?闭包有什么做用?使用闭包的好处是什么?

 

41.什么是变量做用域?

变量的做用域就两种:全局变量和局部变量

全局做用域: 
最外层函数定义的变量拥有全局做用域,即对任何内部函数来讲,都是能够访问的

局部做用域: 
和全局做用域相反,局部做用域通常只在固定的代码片断内可访问到,而对于函数外部是没法访问的,最多见的例如函数内部

<script>
      function fn(){ var innerVar = "inner"; } fn(); console.log(innerVar);// ReferenceError: innerVar is not defined
</script>

须要注意的是,函数内部声明变量的时候,必定要使用var命令。若是不用的话,你实际上声明了一个全局变量!

  <script>
      function fn(){ innerVar = "inner"; } fn(); console.log(innerVar);// result:inner
   </script>

 

再来看一个代码:

 <script>
      var scope = "global"; function fn(){ console.log(scope);//result:undefined
         var scope = "local"; console.log(scope);//result:local;
 } fn(); </script>

颇有趣吧,第一个输出竟然是undefined,本来觉得它会访问外部的全局变量(scope=”global”),可是并无。

这能够算是javascript的一个特色,只要函数内定义了一个局部变量,函数在解析的时候都会将这个变量“提早声明”:

 <script>
      var scope = "global"; function fn(){ var scope;//提早声明了局部变量
         console.log(scope);//result:undefined
         scope = "local"; console.log(scope);//result:local;
 } fn(); </script>

然而,也不能所以草率地将局部做用域定义为:用var声明的变量做用范围起止于花括号之间。
javascript并无块级做用域
那什么是块级做用域?
像在C/C++中,花括号内中的每一段代码都具备各自的做用域,并且变量在声明它们的代码段以外是不可见的,好比下面的c语言代码:

for(int i = 0; i < 10; i++){ //i的做用范围只在这个for循环
} printf("%d",&i);//error

可是javascript不一样,并无所谓的块级做用域,javascript的做用域是相对函数而言的,能够称为函数做用域

<script>
      for(var i = 1; i < 10; i++){ //coding
 } console.log(i); //10 
</script>

 

42.什么是做用域链?什么是执行环境?

个人理解就是,根据在内部函数能够访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问。 

想要知道js怎么链式查找,就得先了解js的执行环境

每一个函数运行时都会产生一个执行环境,而这个执行环境怎么表示呢?js为每个执行环境关联了一个变量对象。环境中定义的全部变量和函数都保存在这个对象中。

全局执行环境是最外围的执行环境,全局执行环境被认为是window对象,所以全部的全局变量和函数都做为window对象的属性和方法建立的。

js的执行顺序是根据函数的调用来决定的,当一个函数被调用时,该函数环境的变量对象就被压入一个环境栈中。而在函数执行以后,栈将该函数的变量对象弹出,把控制权交给以前的执行环境变量对象。 
举个例子:

 

  <script>
      var scope = "global"; 
      function fn1(){
         return scope; 
      }
      function fn2(){
         return scope;
      }
      fn1();
      fn2();
   </script>

 

上面代码执行状况演示: 
执行环境

 

http://www.javashuo.com/article/p-expedgrq-ku.html

 

43.Vue组件

https://www.jianshu.com/p/7e825cd5f086

 

44.优化图片加载的方法有哪些?

a. 图片懒加载,滚动到相应位置才加载图片。

b. 图片预加载,若是为幻灯片、相册等,将当前展现图片的前一张和后一张优先下载。

c. 使用CSSsprite,SVGsprite,Iconfont、Base64等技术,若是图片为css图片的话。

d. 若是图片过大,可使用特殊编码的图片,加载时会先加载一张压缩的特别厉害的缩略图,以提升用户体验。

 

45.什么是token验证?

Token是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并做出相应提示,在这样的背景下,Token便应运而生。

Token是服务端生成的一串字符串,以做客户端进行请求的一个令牌,当第一次登陆后,服务器生成一个Token便将此Token返回给客户端,之后客户端只需带上这个Token前来请求数据即

可,无需再次带上用户名和密码。

 

46.使用基于 Token 的身份验证方法,在服务端不须要存储用户的登陆记录。大概的流程是这样的:

1.客户端使用用户名跟密码请求登陆

2.服务端收到请求,去验证用户名与密码

3.验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端

4.客户端收到 Token 之后能够把它存储起来,好比放在 Cookie 里或者 Local Storage 里

5.客户端每次向服务端请求资源的时候须要带着服务端签发的 Token

6.服务端收到请求,而后去验证客户端请求里面带着的 Token,若是验证成功,就向客户端返回请求的数据

 

47.堆、栈

栈(stack):先进后出;自动分配内存空间,由系统自动释放;使用的是一级缓存,他们一般都是被调用时处于存储空间中,调用完当即释放。

堆(heap):队列优先,先进先出;动态分配内存,大小不定也不会自动释放;存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定;通常由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。

 

48.js中 == 和 === 有什么区别?

== 用于通常比较,=== 用于严格比较,== 在比较的时候能够转换数据类型,=== 严格比较,只要类型不匹配就返回 flase 

 

49.JS语言特色

JS做为脚本语言,它的主要用途是与用户互动,以及操做DOM。这决定了它只能是单线程,不然会带来很复杂的同步问题,也就是同一时刻只能作一件事情。全部任务只能在一个线程上完成,一次只能作一件事。前面的任务没作完,后面的任务只能等着。

可是随着业务的不断增长,只是单纯的单线程模式已经可能没法知足咱们的需求了。因而在html5中新增了后台任务worker API。

浏览器的线程,浏览器中主要的线程包括,UI渲染线程,JS主线程,GUI事件触发线程,http请求线程

 

看一个经典的面试题:

  function a() {
        setTimeout(function () {
            alert(1)
        }, 0);
        alert(2);
    }

    a();

代码中的 setTimeout 设为 0,也就是延迟 0ms,看上去是不作任何延迟马上执行,即依次弹出 “1”、“2”。但实际的执行结果确是 “2”、“1”。其中的缘由得从 setTimeout 的原理提及:

JavaScript 是单线程执行的,也就是没法同时执行多段代码,当某一段代码正在执行的时候,全部后续的任务都必须等待,造成一个队列,一旦当前任务执行完毕,再从队列中取出下一个任务。这也常被称为 “阻塞式执行”。

因此一次鼠标点击,或是计时器到达时间点,或是 Ajax 请求完成触发了回调函数,这些事件处理程序或回调函数都不会当即运行,而是当即排队,一旦线程有空闲就执行。

假如当前 JavaScript 进程正在执行一段很耗时的代码,此时发生了一次鼠标点击,那么事件处理程序就被阻塞,用户也没法当即看到反馈,事件处理程序会被放入任务队列,直到前面的代码结束之后才会开始执行。

setTimeout(fn, 0)的含义是,指定某个任务在主线程最先可得的空闲时间执行,也就是说,当前代码执行完(执行栈清空)之后,尽量的早执行。它在“任务队列”的尾部添加一个事件,所以要等到同步任务和“任务队列”现有的事件都处理完,才会获得执行。

HTML5标准规定了setTimeout()的第二个参数的最小值不得小于4毫秒,若是低于这个值,则默认是4毫秒。在此以前。老版本的浏览器都将最短期设为10毫秒。另外,对于那些DOM的变更(尤为是涉及页面从新渲染的部分),一般是间隔16毫秒执行。这时使用requestAnimationFrame()的效果要好于setTimeout();

注意:setTimeout()只是将事件插入了“任务队列”,必须等当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码消耗时间很长,也有可能要等好久,因此并没办法保证回调函数必定会在setTimeout()指定的时间执行。因此,setTimeout()的第二个参数表示的是最少时间,并不是是确切时间。

settimeout(0)就起到了一个将事件加入到队列中,待执行的一个功能效果!

定时器占用cpu较多,建议酌情使用。

 

50.如何实现js的多线程?

JS为咱们提供了一个Worker类,它的做用就是为了解决这种阻塞的现象。当咱们使用这个类的时候,它就会向浏览器申请一个新的线程这个线程就用来单独执行一个js文件

Web Worker 是运行在后台的 JavaScript,独立于其余脚本,不会影响页面的性能。您能够继续作任何愿意作的事情:点击、选取内容等等,而此时 Web Worker 在后台运行。

Worker就是为了JavaScript 创造多线程环境,容许主线程建立 Worker 线程,将一些任务分配给后者运行。

开启后台线程,在不影响前台线程的前提下作一些耗时或者异步的操做。

由于是不一样的线程,因此主线程与worker线程互不干扰。也不会相互打断。因此在一些场景能够提升页面的流程性。Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(好比用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通讯。

可是,这也形成了 Worker 比较耗费资源,不该该过分使用,并且一旦使用完毕,就应该关闭。

var worker = new Worker(js文件路径);  // 这个语句就会申请一个线程用来执行这个js文件

固然,在主线程中有一些方法来实现对新线程的控制和数据的接收。在这里,咱们只说比较经常使用的几个方法。

//postMessage(msg);
//postMessage方法把在新线程执行的结果发送到浏览器的js引擎线程里
worker.onmessage = function(){
    //获取在新线程中执行的js文件发送的数据 用event.data接收数据
    console.log( event.data )
};
setTimeout( function(){
    worker.terminate();
    //terminate方法用于关闭worker线程
},2000)
    
setTimeout( function(){
    worker = new Worker("js/test22.js");
    //再次开启worker线程
},3000)

 

使用规则:

  1. 必须同源:也就是说js文件的路径必须和主线程的脚本同源。防止了外部引用。
  2. dom限制:在worker线程中不能操做dom(document,window,parent)。注意可使用浏览器的navigator和location对象。
  3. 通信限制:worker线程和主线程不在一个上下文中因此不能直接通信。也就是说主线程定义的变量在worker中也是不能使用的。全部只能经过消息完成。
  4. 提示禁止:worker线程不能alert和confirm,这个不知到具体缘由?
  5. 传值dom:进行消息通信也不能传值dom只能是变量。
  6. ie限制:ie9不能使用!ie9不能使用!ie9不能使用!

https://www.cnblogs.com/yanbigfeg/p/9546599.html#_label0

 

51.浏览器缓存机制

  • 浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识

  • 浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中

以上两点结论就是浏览器缓存机制的关键,它确保了每一个请求的缓存存入与读取

 

根据是否须要向服务器从新发起HTTP请求将缓存过程分为两个部分,分别是强缓存和协商缓存

强缓存:不会向服务器发送请求,直接从缓存中读取资源,在chrome控制台的Network选项中能够看到该请求返回200的状态码,而且Size显示from disk cache或from memory cache。强缓存能够经过设置两种 HTTP Header 实现:Expires 和 Cache-Control

强缓存判断是否缓存的依据来自因而否超出某个时间或者某个时间段,而不关心服务器端文件是否已经更新,这可能会致使加载文件不是服务器端最新的内容,那咱们如何获知服务器端内容是否已经发生了更新呢?此时咱们须要用到协商缓存策略

协商缓存:用户发送的请求,发送到服务器后,由服务器断定是否从缓存中获取资源

  • 协商缓存生效,返回304和Not Modified
  • 协商缓存失效,返回200和请求结果

协商缓存能够经过设置两种 HTTP Header 实现:Last-Modified 和 ETag 。

二者的区别:从名字就能够看出,强缓存不与服务器交互,而协商缓存则须要与服务器交互。

 

若是什么缓存策略都没设置,那么浏览器会怎么处理?

对于这种状况,浏览器会采用一个启发式的算法,一般会取响应头中的 Date 减去 Last-Modified 值的 10% 做为缓存时间。

 

https://www.jianshu.com/p/54cc04190252

 

52.请求头header

HTTP请求中的referrer和referrer-policy :http://www.javashuo.com/article/p-kpqqsspu-t.html

 

53.JS中对象和函数的关系

首先什么是对象?根据W3C上面的解释JS中全部事物都是对象,对象是拥有属性和方法的数据,由此能够看出基本值类型不是对象(number、string、Boolean、undefined、null),剩下的引用类型(函数、数组...)都是对象,也有人说对象是若干属性的集合。

 

函数和对象是什么关系?

1.函数是一种对象。很明显函数是一种对象,但你不能说函数是对象的一种。由于他俩之间是没有包含关系的。

function test() {};
console.log(test instanceof Object);    //    true

二、对象都是经过函数建立的

先来看一个例子

function test() {
    this.name="哈哈"
};
var test2=new test();
console.log(test2 instanceof Object);    //true

这个例子能够说明对象能够被函数建立。那为何要说对象都是经过函数建立的,那对象字面量是否是也是经过函数来建立的,答案是确定的,这是一种语法糖方式。举个简单的例子

var obj={
    name:"哈哈",
    age:"18"
}
var obj=new Object()
obj.name="哈哈";
obj.age="18";

上面的对象字面量实际上是经过下面的构造函数来建立的。而其中的Object是一种函数:

console.log(typeof Object)    //function

经过上面的简单例子咱们能够得出一个结论:对象是经过函数建立的,而函数又是一种对象。那么这是为何呢?这就牵扯到prototype原型

 

54.null 和 undefeated 的区别?

null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN

http://www.javashuo.com/article/p-puklnbrk-gm.html

 

55.es6 class

ES6 的 class 属于一种“语法糖”,因此只是写法更加优雅,更加像面对对象的编程,其思想和 ES5 是一致的

//定义类
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

等同于

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 2);

其中 constructor 方法是类的构造函数,是一个默认方法,经过 new 命令建立对象实例时,class必需要用new命令建立,否则会报错(TypeError: Class constructor Foo cannot be invoked without ‘new’),自动调用该方法。一个类必须有 constructor 方法,若是没有显式定义,一个默认的 consructor 方法会被默认添加。因此即便你没有添加构造函数,也是会有一个默认的构造函数的。通常 constructor 方法返回实例对象 this ,可是也能够指定 constructor 方法返回一个全新的对象,让返回的实例对象不是该类的实例

class继承中,子类必须在constructor方法中调用super方法,不然新建实例时会报错。这是由于子类本身的this对象,必须先经过父类的构造函数完成塑造,获得与父类一样的实例属性和方法,而后再对其进行加工,加上子类本身的实例属性和方法。若是不调用super方法,子类就得不到this对象。 

 

super 这个关键字,既能够当作函数使用,也能够当作对象使用。这两种状况下,它的用法彻底不用。

1.看成函数使用

class A {}
class B extends A {
  constructor() {
    super();  // ES6 要求,子类的构造函数必须执行一次 super 函数,不然会报错。
  }
}

注:在 constructor 中必须调用 super 方法,由于子类没有本身的 this 对象,而是继承父类的 this 对象,而后对其进行加工,而 super 就表明了父类的构造函数。super 虽然表明了父类 A 的构造函数,可是返回的是子类 B 的实例,即 super 内部的 this 指的是 B,所以 super() 在这里至关于 ```A.prototype.constructor.call(this, props)``。

class A {
  constructor() {
    console.log(new.target.name); // new.target 指向当前正在执行的函数
  }
}

class B extends A {
  constructor {
    super();
  }
}
new A(); // A
new B(); // B

能够看到,在 super() 执行时,它指向的是 子类 B 的构造函数,而不是父类 A 的构造函数。也就是说,super() 内部的 this 指向的是 B

 

2.看成对象使用

在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

class A {
  c() {
    return 2;
  }
}

class B extends A {
  constructor() {
    super();
    console.log(super.c()); // 2
  }
}
let b = new B();

上面代码中,子类 B 当中的 super.c(),就是将 super 看成一个对象使用。这时,super 在普通方法之中,指向 A.prototype,因此 super.c() 就至关于 A.prototype.c()。

 

经过 super 调用父类的方法时,super 会绑定子类的 this

class A {
  constructor {
    this.x = 1;
  }
  s() {
    console.log(this.x);
  }
}

class B extends A {
  constructor {
    super();
    this.x = 2;
  }
  m() {
    super.s();
  }
}

let b = new B();
b.m(); // 2

上面代码中,super.s() 虽然调用的是 A.prototytpe.s(),可是 A.prototytpe.s()会绑定子类 B 的 this,致使输出的是 2,而不是 1。也就是说,实际上执行的是 super.s.call(this)

因为绑定子类的 this,因此若是经过 super 对某个属性赋值,这时 super 就是 this,赋值的属性会变成子类实例的属性

  class A {
        constructor() {
            this.x = 1;
        }
    }

    class B extends A {
        constructor() {
            super();
            this.x = 2;
            super.x = 3;
            console.log(super.x); // undefined
            console.log(this.x); // 3
        }
    }

    let b = new B();

上面代码中,super.x 赋值为 3,这时等同于对 this.x 赋值为 3。而当读取 super.x 的时候,调用的是 A.prototype.x,但并无 x 方法,因此返回 undefined。

 

注意,使用 super 的时候,必须显式指定是做为函数,仍是做为对象使用,不然会报错。

class A {}
class B extends A {
  constructor() {
    super();
    console.log(super); // 报错
  }
}

上面代码中,console.log(super); 的当中的 super,没法看出是做为函数使用,仍是做为对象使用,因此 JavaScript 引擎解析代码的时候就会报错。这是,若是能清晰的代表 super 的数据类型,就不会报错。

最后,因为对象老是继承其余对象的,因此能够在任意一个对象中,使用 super 关键字

https://blog.csdn.net/a419419/article/details/82772412

 

56.JS的运行机制?

https://baijiahao.baidu.com/s?id=1615713540466951098&wfr=spider&for=pc

 

57.函数的防抖和节流

https://www.jianshu.com/p/c8b86b09daf0

 

58.javascript判断一个字符串或者数组里面出现最多的元素及其出现的次数

字符串:

  var str = 'aabbccccdddd';

    var obj = {};

    for (var i = 0; i < str.length; i++) {
        if (!obj[str.charAt(i)]) {
            obj[str.charAt(i)] = 1;
        } else {
            obj[str.charAt(i)]++;
        }
    }

    console.log(obj);

    var maxVal = 0;
    var maxStr = '';
    for (var j in obj) {
        if (obj[j] > maxVal) {
            maxVal = obj[j];
            maxStr = j;
        }
    }

    console.log('最多的是:' + maxStr + ',出现了:' + maxVal + '次');

 

数组:

  var arr = [1, 2, 3, 4, 1, 2, 2, 2, 2, 4];

    var obj = {};

    for (var i = 0; i < arr.length; i++) {
        if (!obj[arr[i]]) {
            obj[arr[i]] = 1;
        } else {
            obj[arr[i]]++;
        }
    }

    var maxVal = 0;
    var maxStr = '';

    for (var j in obj) {
        if (obj[j] > maxVal) {
            maxVal = obj[j];
            maxStr = j;
        }
    }
    console.log('最多的是:' + maxStr + ',出现了:' + maxVal + '次');

https://blog.csdn.net/m0_37273490/article/details/80712466

 

59.获取数组最大值?

    var arr = [1,4,2,0,-2,5];

    var max = Math.max.apply(null, arr);

    var max = Math.max(...arr);

    var max = arr.sort().reverse()[0];

    var max = arr.sort(function (a, b) {
       return b - a;
    })[0];

 

60.HTTP协议

当咱们在浏览器地址栏上输入要访问的URL后,浏览器会分析出URL上面的域名,而后经过DNS服务器查询出域名映射的IP地址,浏览器根据查询到的IP地址与Web服务器进行通讯,而通讯的协议就是HTTP协议。

https://blog.csdn.net/aliujiujiang/article/details/81088317

 

61.DNS服务

一般咱们访问一个网站,使用的是主机名或者域名来进行访问的。由于相对于IP地址(一组纯数字),域名更容易让人记住。但TCP/IP协议使用的是IP地址进行访问的,因此必须有个机制或服务把域名转换成IP地址。DNS服务就是用来解决这个问题的,它提供域名到IP地址之间的解析服务。

  

 

62.HTTP与TCP/IP、DNS的关系

HTTP协议与它们之间的关系:

HTTP与TCP/IP、DNS的关系
当客户端访问Web站点时,首先会经过DNS服务查询到域名的IP地址。而后浏览器生成HTTP请求,并经过TCP/IP协议发送给Web服务器。Web服务器接收到请求后会根据请求生成响应内容,并经过TCP/IP协议返回给客户端。

 

63.箭头函数

引入箭头函数有两个方面的做用:更简短的函数而且不绑定this

箭头函数表达式的语法比函数表达式更简洁,而且没有本身的thisargumentssuper或 new.target

这些函数表达式更适用于那些原本须要匿名函数的地方,而且它们不能用做构造函数。 

箭头函数不会建立本身的this,它只会从本身的做用域链的上一层继承this

箭头函数没有prototype属性。

因为 箭头函数没有本身的this指针,经过 call() 或 apply() 方法调用一个函数时,只能传递参数(不能绑定this),他们的第一个参数会被忽略。(这种现象对于bind方法一样成立)

 

不断完善...

相关文章
相关标签/搜索