发文前,小编想先对上一篇文章-css篇纠正错误以及针对文章提出的优化的小伙伴表示感谢,你们的每个建议或意见都很宝贵🌻🌻。
继上两篇文章html篇和CSS篇之后,本篇文章对于常见的有关Javascript
部分的内容进行了大致的整合。文中涉及的知识面还是蛮广的,小编在整理的时候也顺道温习了一遍。
文章字数1.5万+
,篇幅比较长,还是建议收藏吧,慢慢看。所谓温故而知新,本篇文章作为温习知识点还是挺有用的(尤其是准备跳槽的小伙伴抱佛脚尤为有用哈哈哈哈)🥴。
PS: 文中,为了方便阅读,小编一如既往做了分割线。
1.🤪JavaScript 中 this 是如何工作的
首先,在js
中,this
是指正在执行的“所有者”,更确切的说,是指将当前函数作为方法的对象。
javascript
中的this
有一套完全不用于其它语言的对this
的处理机制。在以下五种情况下,this
的指向各不相同。
全局范围
当在全局范围内的时候,使用this
将会指向全局对象(this->window)
;
对象方法调用
这里的this
是在对象中的.当函数被保存为对象的一个属性时,成该函数为该对象的方法,函数中this
的值为该对象。
我们先看个例子:
const object = {
a: 1,
func: function() {
console.log(this.a)
}
}
object.func() //1 (this->object)
function func() {
console.log(this.a)
}
const object = {
a: 1,
b: func
}
object.b() // 1 (this->object)
这里的两个this
指向的是对象object
,此时我们可以这么理解,函数无论在对象内部或外部定义,实现的效果一样。因为作为对象的属性的函数,对于对象来说是独立的。
但是需要注意有时候,对象中的也会存在this绑定丢失的问题,这也是我们下面将的使用apply
或call
调用模式。
使用apply或call调用模式
看下面例子:
function func() {
console.log(this.a)
}
const object = {
a: 1,
b: func
}
const fun = object.b;
fun() // undefined
此时fun()
打印出来的值并不是对象中的1
,而是undefined
。由此可看出,此时的this
指向的并不是object
对象。我们再给代码添加一个全局的a
看看情况:
function func() {
console.log(this.a)
}
const object = {
a: 1,
b: func
}
const fun = object.b;
var a = 2;
fun() // 2
此时的func
打印出来的是全局变量的值--2
,说明此时的this
是指向外部全局变量的。这种情况主要是由因为this的隐式绑定导致的this绑定丢失。
我们可以理解为: 执行“ fun= object.b”之后fun的调用和object.b调用的结果是不同的,因为这个函数赋值的过程无法把b所绑定的this也传递过
决绝方式:通过this
的显示绑定解决。
我们可以通过使用 call
和apply
以及bind
来解决,此时函数内的this
将会被显示设置为函数调用的第一个参数。如下代码:
function func() {
console.log(this.a)
}
const object = {
a: 1,
b: func
}
var a = 2;
const fun = object.b;
fun.call(object) 或者 fun.apply(object) 或者 const funb = fun.bind(object) ; funb() // 1
此时this
指向的就是object
内部的a
,这就解决了this
绑定丢失的问题。
🌈🌈注意 :
bind
是提供了一个可执行的函数,但是本身并不会执行,需要我们手动去执行;call
和apply
它们是提供了一个可立即执行的函数,在绑定this
的同时,也会立即去执行该函数。这也是为什么我们在最后一个bind
方法中再次需要的单独再调用一次funb()
方法的原因。
函数调用
此时的this
也会指向全局对象。我们也可以这么理解:当没有明确的调用对象的时候,行数的this还是在全局范围内的,所以this会绑定到全局的window对象。
调用构造函数
先看个例子:
function func(a) {
this.b = a;
console.log(b)
}
func(20); // 20,此时的b是20
const funb = new func(30)
funb.b; // 30
可以看到,当执行new
操作的时候,会创建一个新的对象,并且将构造函数的this
指向所创建的新对象。
2.请解释原型继承 的原理
有关原型链以及其继承的原理,小编在之前的文章毒鸡汤中,在前面的部分图文结合,已经做了比较详细的介绍,有兴趣的童鞋可以去瞅瞅,小编这里就不过多介绍了(又可以偷懒了)。
3.什么是闭包 (closure),如何使用它,为什么要使用它
有关闭包部分,亦是在毒鸡汤中有所体现。
4. 同步 (synchronous) 和异步 (asynchronous) 函数的区别在哪里
同步
同步(阻塞模式)指的是:当发送一个请求时,需要等待返回,然后才能发送另一个请求。其有个等待的过程。此外,同步也可以避免出现死锁,读脏数据的发生。
异步
异步(非阻塞模式)指的是:当发送一个请求时,不需要等待返回,可以随时发送下一个请求。其不需要等待。
区别: 最明显的就是一个需要等待,一个不需要等待。
拓展: 在项目过程中,可以根据需求,来考虑功能是使用同步还是异步。一般,有些功能为了缩短用户的等待时间,都会优先采用异步的方式;但是对于数据库保存等操作,一般采用的是同步的方式。
5.JavaScript 宿主对象 (host objects) 和原生对象 (native objects) 以及内置(build-in objects)对象的区别
概念
- 宿主对象: 宿主对象不是引擎的原生对象,而是由宿主框架通过某种机制注册到
js
引擎中的对象; - 内置对象: 在引擎初始化阶段就被创建好的对象,是原生对象的一个子集;
- 原生对象: 除了内置对象之外,还包括了一些在运行过程中动态创建的对象;
内容
- 原生对象包括:
Object
,Function
,Array
,String
,Boolean
,Number
,Date
,RegExp
,Error
,EvalError
,RangeError
,ReferenceError
,SyntaxError
,Typerror
,URLError
等; - 内置对象包括:
Global
(全局对象),Math
;(注意所有的内置对象都是原生对象) - 宿主对象包括: 有宿主提供的对象,在浏览器中
window
对象以及其下边的所有子对象(例如dom
等),在node
中是global
以及其子对象,也包含自定义的类对象。
区别
- 内置对象是原生对象的一个子集;前者总在引擎初始化阶段就被创建好对象,而后者还包括了一些在运行过程中动态创建的对象;
- 宿主对象不是引擎的原生对象,而是有宿主框架通过某种机制注册到js引擎当中的对象;
6.以下代码有什么区别:function Person(){}、var person = Person()、var person = new Person()
- 第一:
function Person(){}
是声明了一个名为Person
的函数; - 第二:
var person = Person()
是直接调用了Person
函数,并将返回值作为值赋值给变量person
; - 第三:
var person = new Person()
创建了一个Person
实例对象;
7.什么是变量声明提升 (hoisting)
首先我们先看个例子:
console.log(num); //undefined
var num = 5;
console.log(num) // 5
到这里,有基础的小伙伴可能看出来这是为什么了。没错,就是变量声明提升!一个变量的生命周期包含3个阶段
- 声明--从创建一个新的变量开始,例如:
var num
; - 初始化--初始化变量给变量赋值,例如:
num = 5
; - 使用--使用变量的值,例如
console.log(num)
;
上面的例子其实等价于:
var num;
console.log(num); //undefined 因为变量num提升了,但是值并没有提升,所以打印出来是undefined
num = 5;
console.log(num) // 5
🌈🌈注意: 如果变量是在函数作用域内,那么它的作用域就是函数作用域。否则,它就是全局作用域。
拓展
拓展1之函数优先
函数声明和函数表达式在语法上是的等价的,但是有一点不同的是,
js
引擎加载它们的方式不一样。简单来说就是:函数声明会被提升到其作用域顶部,而函数表达式不会。
具体可以看以下两点:
- 函数声明会提升,但是函数表达式的函数体不会提升;
- 函数是
javascript
的一等公民,当一个变量名和函数同名时,函数声明优先变量声明,并且会忽略同名的变量声明。
拓展2之let,const和var
在此长话短说,总的来说就是let
和const
的声明会形成块级作用域,不存在变量提升且不能重复声明同一变量(或常量)。而var
声明的变量会挂载在window
上,存在变量提升且可以命名重复。
8.什么是 “use strict”; ? 使用其的优缺点
“use strict”
-- 严格模式, ES5
添加的一种运行模式,目的是为了是javascript
在更严格的条件下运行。
优点(设立的目的)
- 消除
js
语法的一些不合理,不严谨之处,减少一些怪异行为; - 消除代码运行的一些不安全之处,保证代码运行安全;
- 提高编译效率,增加运行速度;
- 为未来新版本的
javascript
做好铺垫;
🌈🌈注意: 经过测试,目前IE6-9
都不支持严格模式。
缺点
现在网站的js
一般都会进行压缩,压缩过程中,有些文件使用了严格模式,有些却没有。这种情况下本来是严格模式的文件,被merge
后,这个串就到了文件中间,不仅没有指示严格模式,在压缩后也会浪费字节。
9.什么是事件循环 (event loop)
javascript
是单线程执行的,从上到下一次运行。在js
中分为两个任务,宏任务和微任务。一般情况下,首先执行的是宏任务(就是通常说的第一时间执行所有同步代码),遇到微任务时,先加入队列,宏任务执行完毕再执行微任务。微任务执行完毕之后再往下执行宏任务,执行完后再次执行所有微任务。
简单的理解就是: 宏任务-> 微任务-> 宏任务 ->微任务;
终于详细的执行机制,有兴趣的小伙伴小编建议请移步至毒鸡汤瞅瞅。
10.bind,call 和 apply 的区别
相似之处
- 它们的第一个参数都是
this
要指向的对象; - 都是用来改变函数的
this
指向的; - 都可以利用后继参数传参;
区别
- 执行方面:使用
call
和apply
之后函数可自动执行,但是使用bind
需要手动执行; - 参数接收方面:
call
和apply
接收的第一个参数是在其中运行函数的作用域,不同的是在接收的第二个参数时,apply
接收的是一个数组,而call
接收的是参数列表,需要跟函数保持一一对应。
🌈🌈注意: call
和apply
扩充了函数的作用域。
应用场景
- 如果不需要关心具体有多少参数被传入函数的时候(或者参数较多情况下),可以选用
apply
; - 如果确定函数可以接收多少个参数(或参数较少情况下),并且想一目了然的表达形参和实参的对象关系的,可以选用
call
; - 如果想将来再调用方法,不需要立即得到函数的返回结果的,可以选用
bind
;
🚚...................................................ᴅᴜᴅᴜ!
11. 🤥什么是事件委托以及冒泡事件和默认事件如何阻止
概念: 事件冒泡是指嵌套最深的元素触发一个事件,然后这个事件顺着嵌套顺序在父元素上触发。而事件委托,是利用事件冒泡原理,让自己所触发的事件,让其父元素代替执行。
冒泡阻止方式:使用event.cancelBubble = true
或者event.stopPropgation()
(低于IE9)。
默认事件阻止方式: e.preventDefault();
或return false;
。
12. 如何检查一个数字是否为整数
比较简单的方式是可以将其数字对1进行取模,看看是否存在余数。看以下代码:
function isInt(number) {
return number % 1 === 0;
};
console.log(isInt(2.1)); // false
console.log(isInt(2)); // true
13. 什么是IIFE(立即调用函数表达式)
它是立即调用函数表达式(Immediately-Invoked Function Expression),简称为IIFE
。指的是函数被创建后立即执行。看下面代码:
(function IIFE(){
console.log( "Hello!" );
})();
// "Hello!"
这种立即调用函数表达式一般应用于避免污染全局命名空间条件下。因为 IIFE
(与任何其他正常函数一样)内部的所有变量在其作用域之外都是不可见的。
14. 原型设计模式
原型模式可用于创建新对象,但是它创建的并不是初始化的对象,而是使用原型对象的值进行初始化的对象。原型模式也成为属性模式。
原型模式在初始化业务对象是非常有用,业务对象中的值与数据库的默认值相匹配。原型对象中的默认值被复制到新创建的业务对象中。目前js
在构造新对象及其原型时使用了这个模式。
原型模式包含以下主要角色:
- 抽象原型类: 规定了具体原型对象必须实现的接口;
- 具体原型类: 实现了抽象原型类的
clone()
方法,它是可被复制的对象; - 访问类: 使用具体原型类中的
clone()
方法来复制新的对象;
15. jsonp的原理,以及为什么不是真正的ajax
Jsonp原理: 利用浏览器可以动态的插入一段JS代码并执行;
为什么不是真正的AJAX
- 首先,
ajax
和jsonp
在调用方式上虽然长得差不多(目的一样,都是请求一个url
,然后把服务器返回的数据进行处理),但是ajax
和jsonp
本质上是不同的东西; - 哪里不同?核心不同!
ajax
的核心是通过XmlHttpRequest
获取非本页内容,而jsonp
的核心则是动态添加<script>
标签来调用服务器提供的js
脚本; - 此外,需要注意的是,
ajax
和jsonp
的区别不在于是否跨域。因为ajax
通过服务端代理一样可以实现跨域,jsonp
本身也不排斥同域的数据的获取。还有就是jsonp
是一种方式或者说是非强制协议,如同ajax
一样,它也不一定非要jsonp
格式来传递数据; jsonp
只支持get
请求,ajax
支持get
和post
请求.
16. Javascript的事件流模型都有什么
- “事件冒泡”: 当触发一个节点的事件时,会从当前节点开始,依次触发其祖先节点的同类型事件,直到
DOM
根节点。(逐级向上) - “事件捕获”: 当触发一个节点的事件时,会从
DOM
根节点开始,依次触发其祖先节点的同类型事件,直到当前节点自身。(逐级向下) - “DOM事件流”:
dom
同时支持两种事件模型,但捕获性事件先开始,从document
开始也结束于document
,dom
模型的独特之处在于文本也可以触发事件。简单的说分为三个阶段:事件捕捉, 目标阶段, 事件冒泡
17. new操作符具体干了些啥
首先我们需要明白的是:new
关键字主要的作用还是在于继承。
对于const a = new Foo();
,new
干的事情。如下代码:
const obj = new Object(); // 声明一个新的空对象obj
obj.__propto__ = Person.prototype; // 让obj的__proto__指向函数原型的prototype
Person.call(obj); // this指向obj对象
person = obj; // 将obj对象赋值给person对象
然后我们来捋一捋,new
一共经历了几个阶段?(4个)
- 创建一个空对象;
- 设置原型链;
- 让
Func
的this
指向obj
,并执行Func
函数体; - 判断
Func
(构造函数)的返回值类型;
18. js延迟加载的方式有哪些?
defer
属性(页面load
后执行):脚本会被延迟到整个页面都解析完毕之后再执行。若是设置了defer
属性,就等于告诉浏览器立即下载,但是会延迟执行。注意defer
属性只适用于外部脚本文件。async
属性(页面load
前执行):为了不让页面等待脚本下载和执行,异步加载页面和其他内容。async
同样也只适用于外部文件(不会影响页面加载,但是不能控制加载的顺序)。- 动态创建
DOM
方式; - 使用
jQuery
的getScript()
方法; - 使用
setTimeout
延迟方法; - 让
js
文件最后加载。
19. Flash和ajax各自的优缺点,以及在使用中如何取舍
- 于Flash来说:
flash
是个处理多媒体,矢量图形以及访问机器等;但是对于CSS
,文本处理有不足,不容易被搜索; - 于Ajax来说:
Ajax
对CSS
,文本处理有很好的支持,亦支持搜索;但是对多媒体,矢量图形以及访问机器等不足;
共同点:
- 与服务器的无刷新传递消息;
- 可以检测用户的离线和在线状态;
- 可以操作
DOM
;
20. Cookie在客户机上是如何存储的
cookies
是服务器暂时放在我们电脑里的文本文件,好让服务器来辨认我们的计算机。
当我们在浏览网站的时候,web
服务器会先发送小部分资料放在我们的计算机中,cookies
会帮助我们,将我们在网站上打印的文字或一些选择记录下来,当我们再次访问同一个网站,web
服务器会先检查有没有它上次留下的cookies
资料。
若有,会依据cookies
里面的内容来判断使用者,从而给我们推出相应的网页内容。
🚚...................................................ᴅᴜᴅᴜ!
21. 🤨什么是Json
json
是一种轻量级的数据交换格式;- 独立于语言平台,解析器和库支持许多不同的编程语言;
- 它的语法表示三种类型值:简单值(
number
,string
,boolean
,null
),数组,对象;
22. 线程与进程的区别
一个程序至少有一个进程,一个进程至少有一个线程。线程的划分尺度小于进程,使得多线程程序的并发性高。这里我们可以简单的把进程理解成火车,线程理解为车厢。
区别:
- 线程在进程下运行,不能单独运行(单纯的一节节车厢无法运行);
- 一个进程可以包含多个线程(一辆火车有很多车厢);
- 不同进程之间的数据难以共享(列车在行驶时,乘客很难从一列火车换到另一列火车);
- 同一进程下的线程数据共享便捷(乘客在同一列火车上从一节车厢换到另一节很方便);
- 进程要比线程花费更多的计算机资源(车厢仅仅是跑,或者还要发动动力带它跑,花的力气更多);
- 进程之间互不影响,但是同一个进程中要是有一个线程出现问题将导致整个进程有问题(一辆类车要是某一节车厢出问题比如起火,会导致火车暂停);
- 进程可以拓展到多机,而线程最多扩展到多核
cpu
。(不同的火车可以开在不同的轨道上,而同一火车的车厢只能形式在当前火车行驶的轨道上); - 进程使用的内存地址可以上锁,即一个线程使用某些共享内存时,其他线程必须等它结束才能使用这块内存。(例如使用火车上的洗手间-“互斥锁”);
- 进程使用的内存地址可以限定使用量(例如火车上的卧铺,最多只允许多少个人睡,如果安排满了就需要等待,待有空床位出来了才能进去--“信号量”);
23. 如果网页内容需要支持多语言,需要考虑些什么
- 应用字符集的选择,选择utf-8编码;
- 语言书写习惯以及导航结构;
- 数据库驱动型网站;
24. JavaScrip的一些编写原则
- 不要再同一行声明多个变量;
- 使用
===
和!==
来做比较; - 使用字面量的方式来创建数组、对象,来代替
new Array
这种形式; switch
语句必须要带default
分支;fon-in
循环中的变量,用var
关键字说明作用域,防止变量污染;- 尽可能的用三元表达式代替
if..else..
条件语句; - 比较数据类型以下
6
中情况是false
,false
、""
、0
、null
、undefined
、NaN
;其余的都是true
; - 数据类型检测用
typeof
,对象类型检测用instanceof
; - 异步加载第三方的内容; ...
25. 闭包是什么,有什么特性,对页面有什么影响
闭包是能够读取其他函数内部变量的函数,使得函数不被GC
回收。但是滥用闭包,会导致内存泄漏;
26. document load 和document ready的区别
- document load:是在结构和样式,外部
js
和图片加载完才执行js; - document ready: 是
dom
树创建完成就执行的方法,原生是没有这种方法的。
27. 如何中断ajax请求
- 设置超时时间让
ajax
自动断开; - 手动停止
ajax
请求,其核心是调用XML
对象的abort
方法,ajax.abort()
;
28. 宏任务和微任务
- 宏任务: 当前调用栈中执行的任务称为宏任务。包括整体代码
script
,setTimeout
,setInterval
; - 微任务: 当前(此次事件循环中)宏任务执行完,在下一个宏任务开始之前需要执行的任务为微任务。包含回调事件,
Promise
,process.nextTick
(node.js);
🌈🌈注意: 宏任务中的事件放在callback
queue
中,由事件触发线程维护;微任务的事件放在微任务队列中,由js
引擎线程维护。
29. get和post的区别
get
传参方式是通过地址栏URL传递,是可以直接看到get
传递的参数,post
传参方式参数URL不可见,get
把请求的数据在URL
后通过?
连接,通过&
进行参数分割。psot
将参数存放在HTTP
的包体内;get
传递数据是通过URL
进行传递,对传递的数据长度是受到URL
大小的限制,URL
最大长度是2048
个字符。post
没有长度限制;get
回退不会有影响,post
回退会重新进行提交;get
请求可以被缓存,post
不可以被缓存;get
请求只URL
编码,post
支持多种编码方式;get
只支持ASCII
字符,post
提交没有字符类型限制;get
请求的记录会留在历史记录中,post
请求不会留在历史记录;
30. 常见的http的响应码及含义
(1)、1xx(临时响应)
100
: 请求者应当继续提出请求。101
(切换协议) :请求者已要求服务器切换协议,服务器已确认并准备进行切换。
(2)、2xx(成功)
200
: 请求成功并返回正确接口结果;201
: 表示资源被正确创建。202
: 请求正确,但结果正在处理中,这时候客户端可以通过轮询等机制继续请求。203
: 非授权信息,服务器已成功处理了请求,但返回的信息可能来自另一个源;204
: 无内容,服务器成功处理了请求,但没有返回任何内容;205
: 重置内容,服务器成功处理了请求,内容被重置;206
: 部分内容,服务器成功处理了部分请求;
(3)、3xx(已重定向)
300
: 已经请求成功,但是有多个结果返回;301
: 请求成功,但是资源被永久转移;302
: 临时移动,请求的网页暂时跳转到其他页面,即暂时重定向;303
: 使用get访问新的地址来获取资源;304
: 请求的资源并没有被修改过;305
: 使用代理,请求者应该使用代理访问该页面;306
: 临时重定向,请求的资源临时从其他位置响应;
(4)、4xx(请求错误)
400
: 请求出现错误,比如请求头不对等;401
: 没有提供认证信息。请求的时候没有带上Token
等;402
: 为以后需要所保留的状态码;403
: 请求的资源不允许访问,无权限;404
: 访问页面不存在;405
: 方法禁用,服务器禁用了请求中指定的方法;406
:不接受,无法使用请求的内容响应请求的页面;407
: 请求者需要使用代理授权;408
: 服务器请求超时;409
: 服务器在完成请求时发生冲突;410
:请求的资源已永久删除;411
: 需要有效长度。服务器不接受不含有效内容长度标头字段的请求;412
: 服务器未满足请求者在请求中设置的其中一个前提条件;413
: 请求实体过大,超出服务器的处理能力;414
: 请求网址过长,服务器无法处理;415
: 请求格式不被请求页面支持;416
: 页面无法提供请求的范围;417
: 服务器未满足期望请求标头字段的要求;
(5)、5xx(服务器错误)
500
: 服务器内部错误,无法完成请求;501
: 请求还没有被实现,服务器不具备完整的请求功能;502
: 错误网关,服务器作为网关或代理,从上游服务器收到无效响应;503
: 服务不可用;504
:网关超时,服务器作为网关或代理。但是没有及时从上游服务器收到请求;505
:HTTP
版本不支持,服务器不支持请求中所用的HTTP
协议版本。
🚚...................................................ᴅᴜᴅᴜ!
31. 😤IE和DOM事件流的区别
- 从执行顺序看:
IE
采用的是冒泡型事件,而DOM
是先捕获后冒泡事件;
我们可以看个例子:
<body>
<div>
<button>点击</button>
</div>
</body>
// 冒泡型事件模型: button->div->body (IE事件流)
// 捕获型事件模型: body->div->button (Netscape事件流)
// DOM事件模型: body->div->button->button->div->body (先捕获后冒泡)
- 参数方面看,低版本的
ie
没有回调函数,只能进行冒泡; - 从第一个参数是否加"on"问题看,低版本IE不支持
addEventListener()
,支持attachEvent
,第一个参数需要加on
; - 从this的指向问题看,
IE
指向windows
,不指向触发的函数;
32. javascript是一种什么样的语言
- 解释性脚本语言,代码不能进行预编译;
- 主要用来向
html
页面添加交互行为; - 可以直接嵌入到
html
页面,或单独写成js文件。建议单独写成文件,有利于结构和行为分离,利于维护; - 跨平台性,在绝大多数浏览器支持下,可以在多种平台下运行,例如
windows
,linux
等;
33. DOM和BOM是什么
首先我们需要知道:javascript是由ECMAScript,DOM,BOM三部分构成的。
ECMAScript
是一种语言,是对规定的语法,操作,关键字,语句的一个描述,javascript
实现了ECMAScript
;DOM
是文档对象模型,包括了获取元素,修改样式以及操作元素等三方面的内容,也是通常我们用的最多的操作,其提供了很多兼容性的写法;BOM
是浏览器对象模型,包括浏览器的一些操作,window.onload
,window.open
等还有浏览器时间,监听窗口的改变onresize
,监听滚动事件onscroll
等;
34. 如何实现多个标签之间的通信
- 调用 localStorage;
(1)、在一个标签内使用localStorage
。setItem(key, value)
添加(删除或修改)内容;
(2)、在另一个标签页面监听storage
事件;
(3)、得到localStorage
存储的值,即可实现不用页面之间的通信。
- 调用 cookie+setInterval();
(1)、将要传递的信息存储在cookie
中,可以设置定时读取cookie
的信息,即可随时获取想要传递的信息。
- 使用 Webworker;
(1)、webworker
作为浏览器的一个新特性,可以提供一个额外的线程来执行一些js代码,并且对浏览器用户界面不影响;
(2)、普通的Webworker
用 new worker()
即可创建,这种webworker
是当前页面专有的。然后还有种共享worker(SharedWorker)
,这种是可以多个标签页、iframe
共同使用;
- 使用 SharedWorker;
(1)、SharedWorker
可以被多个window
共同使用,但必须保证这些标签页都是同源的(相同的协议,主机和端口号);
35. 哪些操作会造成内存泄露
内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。
以下几点回造成内存泄露:
- 过量使用闭包会引起内存泄露(解决:将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中,删除对
dom
的引用); - 控制台日志(解决:项目完成后记得删除多余的控制台打印);
- 循环,也就是两个对象彼此引用且彼此保留;
setTimeout
的第一个参数是字符串而不是函数的时候也会造成内存泄露(解决:尽量不要将第一个参数定义为字符串);- 意外的全局变量也会引起内存泄漏(解决:使用严格模式避免)。
- 没有清理
DOM
元素(解决: 手动删除);
36. js垃圾回收的几种方式
javascript
具有自动垃圾回收机制,垃圾器回收会按照固定的时间间隔周期性的执行。
常见的垃圾回收机制有两种: 标记清除,引用计数。
标记清除
原理: 当变量进入环境时,将这个变量标记为“进入环境”。当变量离开时,则将其标记为“离开环境”。标记“离开环境”的就回收内存。
工作流程:
- 垃圾回收器,在运行的时候会给存储在内存中的所有变量都加上标记;
- 去掉环境中的变量以及被环境中的变量引用的变量的标记;
- 再被加上标记的会被视为准备删除的变量;
- 垃圾回收器完成内存清除工作,销毁那些带标记的值并回收他们所占用的内存空间;
引用计数
原理: 跟踪记录每个值被引用的次数,声明一个变量,并将引用 类型赋值给这个变量,则这个值的引用次数+1
,当变量的值变成了另一个,则这个值的引用次数-1
,当值的引用次数为0
的时候,就回收。
工作流程:
- 声明了一个变量并将一个引用类型的值赋值给这个变量,这个引用值的引用次数就是
1
; - 同一个值又被赋值给另一个变量,这个引用类型值此时的引用次数
+1
; - 当包含这个引用类型值的变量又被赋值成另一个值,那么这个引用呢性值的引用次数
-1
; - 当引用次数变成0时,说明目前无法访问此值;
- 当垃圾收集器下一次运行时,它会释放引用次数是
0
的值所占的内存;
37. 什么放在内存中?什么不放在内存中?
- 基本类型(
Boolean
,String
,Number
,Null
,Undefined
,Symbol
(新增))的值保存在内存中。从一个变量向另一个变量赋值基本类型的值,会创建这个值的一个副本; - 引用数据类型(
object
)的值是个对象,保存在堆内存中。
🌈🌈注意:
- 包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针。从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终指向的都是同一个对象;
javascript
不允许直接访问内存中的位置,也就是不能直接访问操作对象的内存空间。在操作对象时,实际上在操作对象的引用而不是实际的对象;
38. 堆和栈的区别
(1)、堆和栈空间分配的区别
- 堆(操作系统): 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收,分配方式类似于链表;
- 栈(操作系统): 由操作系统自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;
(2)、堆和栈缓存方式的区别
- 堆是存放在二级缓存中的,声明周期由虚拟机的垃圾回收算法决定(这里,并不是成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来的低一些;
- 栈使用的是一级缓存,它们通常都是被调用时处于缓存空间中,调用完毕立即释放;
(3)、堆和栈结构区别
- 堆(数据结构):堆可以被看成是一棵树,如: 堆排序;
- 栈(数据结构):是一种先进后出的数据结构;
39. 在浏览器中输入URL到整个页面显示在用户面前时这个过程中到底发生了什么(详解)
(1)、DNS解析
- 检查浏览器自身的
DNS
缓存; - 若没有,搜索操作系统自身的
DNS
缓存; - 若没有,尝试读取
hosts
文件; - 若没有,可向本地配置的首选
DNS
服务器发起请求; .win
系统若没有好到,可以操作系统查找NetBIOS name cache
或查询wins
服务器或广播查找或读取LMHOSTS文件;
(若以上都没有,则解析失败)
(2)、TCP三次握手
(3)、浏览器向服务器发送http请求
一旦建立了TCP
链接,web
浏览器就会向web
服务器发送请求命令。
(4)、浏览器发送请求头信息
浏览器发送其请求命令之后,还要以头信息的形式想web
服务器发送一些别的信息,之后浏览器发送了一空白行开通知服务器,它已经结束了该头信息的发送。
(5)、服务器处理请求
服务器收到http
请求之后,确定用相应的一眼来处理请求。读取参数并进行逻辑操作后,生成指定的数据。
(6)、服务器做出响应
客户端向服务器发送请求后,服务端向客户端做出应答。
(7)、服务器发送应答头信息
正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据以及被请求的文档。
(8)、服务器发送数据
web
服务器向浏览器发送信息后,它会发送一个空白行来表示头信息的发送到此结束。接着,它会以Content-Type
应答头信息所描述的格式发送用户所请求的实际数据。
(9)、 TCP关闭(四次挥手)
一般情况下,一旦web
服务器向浏览器发送了请求数据,它就要关闭tcp
链接。如果浏览器或服务器在其头信息加入了Connection:keep-alive
,则会保持长连接状态,也就是TCP链接在发送后仍保持打开状态,浏览器可以继续通过仙童的链接发送请求。
(优点:保持链接节省了为每个请求建立新链接所属的时间,还节约了网络宽带 )
40. 继承的方法有哪些
- 原型链继承;
- 构造函数继承;
- 实例继承;
- 组合继承;
- 拷贝继承;
- 寄生组合继承;
🚚...................................................ᴅᴜᴅᴜ!
41. 🥴JavaScript和ASP脚本相比,哪个更快
一般情况下,javascript
会更快。javascript
是一种客户端语言,因此它不需要web
服务器的协助来执行。另一方面,ASP
是服务端语言,因此总是比javascript
慢。但是需要注意的是:javascript
现在也可以用于服务端语言(例如nodejs
)。
42. Java和JavaScript之间的区别
- 首先,
java
是一门十分完整,成熟的编程语言;相比之下,javascript
是一个可以被引入HTML
页面的编程语言。这两种语言并不是完全相互依赖的,而是真对不同的意图而设计的。 - 其次,
java
是一种面向对象编程(OOPS
)或结构化的编程语言,类似于C++
和C
;而javascript
是客户端脚本语言,它被称为非结构化编程。
43. 什么是负无穷大
负无穷大是javascript
中的一个数字,可以通过将负数除以零得到。
44. 什么是未声明和未定义的变量
- 未声明的变量是指程序中不存在且为声明的变量。如果程序尝试读取为声明的变量的值,运行会报错;
conosle.log(b);
// Uncaught ReferenceError: conosle is not defined
at <anonymous>:1:1
- 未定义的变量是在程序中声明但是尚未赋予任何值的变量。如果程序中使用了未定义的变量的值,会返回一个
undefined
。
let c;
console.log(c); // undefined
45. javascript中有几种定时器以及其如何工作
定时器用于在设定的时间执行一段代码,或者在给定的时间间隔内重复该代码。通过函数setTimeout
、setInterval
和clearInterval
来完成。
- setTimeout(
function
,delay
)函数用于移动在所述延迟之后调用特定功能的定时器; - setInterval(
function
,delay
)函数用于在提到的延迟中重复执行给定的功能,只有在取消时才能停止; - clearInterval(
id
)函数指示定时器停止;
🌈🌈注意: 定时器在一个线程内运行,因此事件可能需要排队等待执行;
46. ViewState和SessionState有什么区别
- ViewState:特定于会话中的页面;
- SessionState: 特定于可在
web
应用程序中的所有页面上访问的用户特定数据;
47. delete操作符的功能是什么
delete
操作符用于删除程序中的所有变量或对象,但是不能删除使用var
关键字声明的变量。
48. 5 + 8 + '7' 和 5 + '8' + 7 的结果是啥
console.log(5 + 8 + '7'); // 137
console.log(5 + '8' + 7); // 587
可以这样理解:连续的整数可以直接相加,字符串直接相连。
49. 在JavaScript中使用innerHTML的缺点是什么
- 内容随处可见;
- 不能像‘追加到
innerHTML
’一样使用; - 即使使用
+=like "innerHTML = innerHTML + 'html'"
,旧的内容仍然会被html
替换; - 整个
innerHTML
内容被重新解析并构建成元素,因此它的速度会慢很多; innerHTML
不提供验证,因此可能会在文档中插入有效的和破坏性的HTML
并将其中断;
50. JavaScript中不同类型的错误有几种
JS的错误类型一般包含六种常见的派生错误以及手动抛出错误类型。
(1)、常见的几种错误类型
- SyntaxError: 语法错误,一般指解析代码时发生的语法错误;
- ReferenceError:引用错误,一般指引用一个不存在的变量时发生的错误。
- TypeError: 类型错误,一般是变量或参数不是预期类型时发生错误。
- EvalError eval(): 函数执行错误,一般指当
eval()
函数没有被正确执行时,会抛出evalError
错误; - RangeError: 范围错误,一般指当一个值超出有效范围时发生的错误。
🚚...................................................ᴅᴜᴅᴜ!
51. 🥱延迟脚本在JavaScript中的作用
一般情况下,当页面首先加载脚本时,加载期间页面的HTML
代码将会暂停解析,直到脚本加载完才能执行。
所以会出现这么一种情况,就是当服务器速度很慢或者脚本很沉重的情况下,会导致网页延迟。在使用Defer
时,脚本会延迟执行直到html
解析器运行完成。这极大程度上减少了加载时间,提升了显示速度。
52. decodeURI()和encodeURI()是什么
encodeURI()
用于将URL
转为十六进制编码,而decodeURI()
用于将编码的URL
转换成正常的URL
。
53. hash(哈希)表是什么
哈希表(亦称散列表),是根据关键码值直接进行访问的数据结构。也就是说,它通过把关键码映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数也称散列函数,存放记录的数组叫做散列表。
54. 节点有几种类型
一般情况下,节点至少拥有nodeType
(节点类型)、nodeName
(节点名称)和nodeValue
(节点值)。
nodeType
属性返回节点类型的常数值。不同的类型对应不同的常数值,12种类型分别对应1到12的常数值,如下:
- 元素节点 :
Node.ELEMENT_NODE(1)
; - 属性节点:
Node.ATTRIBUTE_NODE(2)
; - 文本节点:
Node.TEXT_NODE(3)
; - CDATA节点:
Node.CDATA_SECTION_NODE(4)
; - 实体引用名称节点:
Node.ENTRY_REFERENCE_NODE(5)
; - 实体名称节点:
Node.ENTITY_NODE(6)
; - 处理指令节点:
Node.PROCESSING_INSTRUCTION_NODE(7)
; - 注释节点:
Node.COMMENT_NODE(8)
; - 文档节点:
Node.DOCUMENT_NODE(9)
; - 文档类型节点:
Node.DOCUMENT_TYPE_NODE(10)
; - 文档片段节点:
Node.DOCUMENT_FRAGMENT_NODE(11)
; - DTD声明节点:
Node.NOTATION_NODE(12)
;
(本部分为扩充内容,内容来自度娘🌻🌻)
55. innerHTML和outerHTML的区别
innerHTML
(元素内包含的内容);outerHTML
(自己以及元素内的内容);
56. offsetWidth offsetHeight和clientWidth clientHeight间的区别
offsetWidth/offsetHeight
(content
宽/高 +padding
宽/高 +border
宽/高);clientWidth/clientHeight
(content
宽/高 +padding
宽/高);
57. 几种减低页面加载时间的方法
- 压缩
CSS
、JS
文件; - 合并
CSS
、JS
文件,减少http
请求; - 外部
JS
、CSS
放在最底层; - 减少
DOM
操作,尽可能使用变量代替不必要的DOM
操作; - 优化图片文件,减小其尺寸,特别是缩略图;
- 使用多域名负载网页内的多个文件、图片;
- 服务器开启
gzip
压缩;
58. 描述AJAX的工作原理
- 第一步: 创建
AJAX
对象(XMLHttpRequest/ActiveXObject(Microsoft.XMLHttp)
); - 第二步: 使用
open
打开连接,格式为open
(请求方式,'请求路径',同步/异步); - 第三步: 发送
send()
; - 第四步:当
ajax
对象完成第四步(onreadystatechange)
,数据接收完成。再判断对象状态码(readystate)
当状态码为成功接收的状态码时,HTTP
响应完全接收 。 再判断http
响应状态(200-300
之间或者304
),(缓存)执行回调函数 获取的数据转成字符串格式(responseText)
。
缺点:
- 对搜索引擎不友好;
- 跨域问题的限制;
- 要实现
ajax
下的前后退功能成本比较大;
59. http的cache机制,以及200状态下如何实现 from cache
含义
浏览器缓存(Browser Caching)是为了加速浏览,浏览器在用户磁盘上岁最近请求过的文档进行存储,当用户再次访问这个文档时,浏览器会从本地磁盘显示此文档,从而提升页面加载速率。
cache的作用
- 减少延迟,让网站的运行速度更快,带来更好的用户体验;
- 避免网络拥塞,减少请求量,减少输出带宽;
实现手段
cache-control
中的max-age
是实现内容cache
的重要手段,常用的策略有以下三种:
max-age
和ETag
的组合;- 仅
max-age
; max-age
和Last-Modified
(If-Modified-Since)的组合;
拓展
在此,拓展一下有关强制缓存(200)和协商缓存(304)部分的内容。
- 强制缓存(也称强缓存),指当浏览器去请求某个文件的时候,服务端就在
respone header
里面对该文件做了缓存配置。强制缓存不会向服务器发送请求,直接从缓存中读取资源,在chrome
控制台的network
选项中可以看到该请求返回200
的状态码; - 协商缓存:强制缓存给资源设置了过期时间,在未过期时,可以说是给用户自给自足用的。但是当资源过期时,就需要去请求服务器,这时候请求服务器的过程就可以设置成协商缓存。协商缓存就是需要客户端和服务端进行交互的。协商缓存将缓存信息中的
Etag
和Last-Modified
通过请求发给服务器,由服务器校验,返回状态码304
时,浏览器就可以直接使用缓存。
共同点: 都是从客户端中读取数据;
区别: 强缓存不会发出请求,协商缓存会发出请求。
缓存中header(头部)的参数:
(1)、强制缓存:
- Expires(常用):
response header
里的过期时间,浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存。 - Cache-Control(常用):当值设为
max-age=120
时,则代表在这个请求正确返回时间(浏览器也会记录下来)的2
分钟内再次加载资源,就会命中强缓存。 - no-cache:不使用本地缓存。需要使用缓存协商,来验证是否过期;
- no-store:不可缓存;
- public:客户端和代理服务器都可缓存;
- private:只能有客户端缓存;
(2)、协商缓存
- Etag:即文件
hash
,每个文件唯一。web
服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定); - If-None-Match:当资源过期时(使用
Cache-Control
标识的max-age
),发现资源具有Etag
声明,则再次向web
服务器请求时带上头If-None-Match
(Etag的值)。web
服务器收到请求后发现有头If-None-Match
则与被请求资源的相应校验串进行比对,决定是否命中协商缓存; - Last-Modify/If-Modify-Since:文件的修改时间,精确到秒。浏览器第一次请求一个资源的时候,服务器返回的
header
中会加上Last-Modify
,Last-modify
是一个时间标识该资源的最后修改时间;当浏览器再次请求该资源时,request
的请求头中会包含If-Modify-Since
,该值为缓存之前返回的Last-Modify
。服务器收到If-Modify-Since
后,根据资源的最后修改时间判断是否命中缓存;
🌈🌈注意:
Etag
要优于Last-Modified
;- 在优先级上,服务器校验优先考虑
Etag
; - 在性能上,
Etag
要逊于Last-Modified
。
60. 什么是虚拟DOM,为什么要使用以及和真实DOM的区别
含义及使用
这里,小编的理解是:虚拟DOM
是真实DOM
的内存表示,是一种编程概念,一种模式。它的作用是判断DOM
是否改变、哪些部分需要被重新渲染。这样,不需要操纵真实的DOM
,同时极大的提高了React
的性能。
虚拟DOM
使用diff
算法,当我们多次修改某一部分的内容时,首先在虚拟DOM
树从上至下进行同层比对(不影响真实DOM
),上层发生变化,下层重新渲染,直到最后修改完成,再在真实DOM
中渲染。
使用虚拟DOM
的原因是,可以极大程度上减少DOM
节点的回流和重绘问题,节约资源,提升运行效率。
区别
- 虚拟
DOM
不会进行重排和重绘; - 虚拟
DOM
进行频繁的修改,然后一次性比较并修改真实DOM
中需要修改的部分,最后进行回流和重绘,有效的减少了过多DOM
节点回流和重绘资源消耗的问题; - 虚拟
DOM
有效降低大面积(真实DOM
节点)的回流和重绘,因为最终与真实DOM
比较差异,可以局部渲染。
🚚...................................................ᴅᴜᴅᴜ!
61. 🤫跨域以及解决办法
协议、域名、端口号不同--跨域(也可以理解为协议、域名、端口号相同--同源策略)
解决跨域的几种办法:
document.domain + iframe
(只有在主域相同的情况下才能使用);- 动态创建
script
; location.hash + iframe
;window.name + iframe
;postMessage
(HTML5
中的XMLHttpRequest Level 2
中的API
);CORS
(跨域资源共享);jsonp
;websockets
;
62. 常谈的CSRF和XSS
XSS(Cross Site Scripting)
跨站脚本攻击,黑客将恶意脚本代码植入到页面中从而实现盗取用户信息等操作(注意这里操作的是用户,攻击的方式只是代码的嵌入)。
预防措施:
- 对输入,输出的结果进行必要的转义;
- 尽量使用
post
,对get
使用时尽量对路径长度做限制; - 使用
httponly
来方式黑客通过脚本获取用户cookie
数据。 - 于客户本身,养成良好习惯,提高警惕,不随意点来陌生链接;
CSRF(cross-site request forgery)
跨站请求伪造,黑客伪装成用户身份来执行一些非用户自愿的恶意以及非法操作(注意,这里是黑客伪装成用户操作)。
预防措施:
- 运用验证码;
- 使用
token id
令牌; - 判断请求的
reFerer
是否正确;
区别
CSRF
需要登陆后操作,XSS
不需要;CSRF
是请求页面api
来实现非法操作,XSS
是向当前页面植入js
脚本来修改页面内容。
63. 如何看待AMD和CommonJS
浏览器端异步和服务器端同步的模块化编程规范。
CommonJS:NodeJS
,webpack
是CommonJS
规范的主要实践者,它有四个重要的环境变量为模块化的实现提供支持:module
、exports
、require
、global
。实际使用时,用module.exports
定义当前模块对外输出的接口(不推荐直接用exports
),用require
加载模块。
CommonJS
用同步的方式加载模块。在服务端,模块文件都存放在本地磁盘,读取非常快,所以这样做不会有问题。但是在浏览器端,限于网络原因,更合理的方案是使用异步加载。
`exports`和`module.export`区别:
`exports`:对于本身来讲是一个变量(对象),它不是`module`的引用,它是`{}`的引用,它指向`module.exports`的`{}`模块。只能使用`.`语法 向外暴露变量。
`module.exports`:`module`是一个变量,指向一块内存,`exports`是`module`中的一个属性,存储在内存中,然后`exports`属性指向`{}`模块。既可以使用`.`语法,也可以使用`=`直接赋值。
AMD和require.js:AMD
规范采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。一般用于客户端。
CMD和sea.js:CMD
是另一种js
模块化方案,它与AMD
很类似,不同点在于:AMD
推崇依赖前置、提前执行,CMD
推崇依赖就近、延迟执行。
*ES6: ES6
在语言标准的层面上,实现了模块功能,而且实现得相当简单,旨在成为浏览器和服务器通用的模块解决方案。其模块功能主要由两个命令构成:export
和import
。export
命令用于规定模块的对外接口,import
命令用于输入其他模块提供的功能。
64. 有几种匿名函数(没有定义函数名的函数)用例
- 定义回调函数;
- 立即执行函数;
- 作为返回值的函数;
- 使用方法为
var func = function() {};
定义的函数;
65. null,undefined 或 undeclared的区别以及如何检测
区别:
- null: 未定义的属性;
- undefined: 定义但是为赋值的为
undefined
; - undecleared:
javascript
访问不会报错;
检测方式:
null
是一种特殊的object
,表示无值;
console.log(typeof null); // object
const a = null;
if(!a && typeof(a) !== 'undefined' && a!==0) {
alert('a is null')
} else {
alert('a is not null')
}
undefined
: 是声明但未赋值的变量;
const a = undefined;
if(typeof(a) === 'undefined') {
alert('a is undefined')
} else {
alert('a is not undefined')
}
undeclared
:undeclared
是一种语法错误,不是数据类型,是未声明也未赋值的变量。
🌈🌈注意JavaScript
访问时js引擎不会报错,会把它当成全局变量,即当成window的属性。
67. 可变 (mutable) 和不变 (immutable) 对象的区别
- 可变(mutable): 在
JS
中,对象是引用类型的数据,其优点在于频繁的修改对象时都是在原对象的基础上修改的,并不需要进行重新创建,这样就可以有效的利用内存,不会造成内存空间的浪费; - 不可变(immutable): 每一次修改一个
immutable
对象时,都会创建一个新的不可变对象,在新对象上的操作不会影响到原对象的数据。
68. 使用 Promises 而非回调 (callbacks) 优缺点是什么
Promise
是异步编程的一种解决方案,比传统的解决方案 回调函数和事件 更合理和更强大。它由社区最早提出和实现,ES6
将其写进了语言标准,统一了用法,原生提供了Promise
对象。
所谓Promise
,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise
是一个对象,从它可以获取异步操作的消息。Promise
提供统一的API
,各种异步操作都可以用同样的方法进行处理。
有了Promise
对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise
对象提供统一的接口,使得控制异步操作更加容易。
但Promise
同时存在一些缺点,例如:
- 第一: 无法取消
Promise
,一旦新建它就会立即执行,无法中途取消; - 第二:如果不设置回调函数,
Promise
内部抛出的错误,不会反应到外部; - 第三:当处于
Pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
69. 浏览器特性检测,特性推断和浏览器 UA 字符串嗅探的区别
- 特性检查更适合针对实现了特定特性的浏览器进行操作。
UA
字符串由于被浏览器厂商可以随意修改,因此给使用者的感觉不太靠谱。
70. 理解 Function.prototype.bind
Function.prototype.bind
方法会创建一个新的函数,当这个新函数被调用时,它的this
值是传给bind()
的第一个参数,它的参数是bind()
的其它参数和其原本的参数。
71. 持续更新ing🍀🍀
⏳⏳ ......
写在最后
关于javascript
部分的整理,就先整理到这里吧,后继会持续更新。有关开发性能优化篇小编还在整理当中,但是由于最近项目压身,可能会延迟一丢丢吧(生活不易且珍惜🌻🌻)。
整理的过程中,难免会有疏漏,若是看到有误或者需要补充的知识点,欢迎留言小编💌💌。