javascript篇--1.6万字带你回忆那些遗忘的JS知识点

12,936 阅读47分钟

发文前,小编想先对上一篇文章-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绑定丢失的问题,这也是我们下面将的使用applycall调用模式。

使用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的显示绑定解决。

我们可以通过使用 callapply以及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是提供了一个可执行的函数,但是本身并不会执行,需要我们手动去执行;
  • callapply它们是提供了一个可立即执行的函数,在绑定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

在此长话短说,总的来说就是letconst的声明会形成块级作用域,不存在变量提升且不能重复声明同一变量(或常量)。而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指向的;
  • 都可以利用后继参数传参;

区别

  • 执行方面:使用callapply之后函数可自动执行,但是使用bind需要手动执行;
  • 参数接收方面callapply接收的第一个参数是在其中运行函数的作用域,不同的是在接收的第二个参数时,apply接收的是一个数组,而call接收的是参数列表,需要跟函数保持一一对应。

🌈🌈注意callapply扩充了函数的作用域

应用场景

  • 如果不需要关心具体有多少参数被传入函数的时候(或者参数较多情况下),可以选用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

  • 首先,ajaxjsonp在调用方式上虽然长得差不多(目的一样,都是请求一个url,然后把服务器返回的数据进行处理),但是ajaxjsonp本质上是不同的东西;
  • 哪里不同?核心不同!ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本;
  • 此外,需要注意的是,ajaxjsonp的区别不在于是否跨域。因为ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。还有就是jsonp是一种方式或者说是非强制协议,如同ajax一样,它也不一定非要jsonp格式来传递数据;
  • jsonp只支持get请求,ajax支持getpost请求.

16. Javascript的事件流模型都有什么

  • “事件冒泡”: 当触发一个节点的事件时,会从当前节点开始,依次触发其祖先节点的同类型事件,直到DOM根节点。(逐级向上)
  • “事件捕获”: 当触发一个节点的事件时,会从DOM根节点开始,依次触发其祖先节点的同类型事件,直到当前节点自身。(逐级向下)
  • “DOM事件流”dom同时支持两种事件模型,但捕获性事件先开始,从document开始也结束于documentdom模型的独特之处在于文本也可以触发事件。简单的说分为三个阶段:事件捕捉目标阶段事件冒泡

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个)

  • 创建一个空对象;
  • 设置原型链;
  • Functhis指向obj,并执行Func函数体;
  • 判断Func(构造函数)的返回值类型;

18. js延迟加载的方式有哪些?

  • defer属性(页面load后执行):脚本会被延迟到整个页面都解析完毕之后再执行。若是设置了defer属性,就等于告诉浏览器立即下载,但是会延迟执行。注意defer属性只适用于外部脚本文件。
  • async 属性(页面load前执行):为了不让页面等待脚本下载和执行,异步加载页面和其他内容。async同样也只适用于外部文件(不会影响页面加载,但是不能控制加载的顺序)。
  • 动态创建DOM方式;
  • 使用jQuerygetScript()方法;
  • 使用setTimeout延迟方法;
  • js文件最后加载。

19. Flash和ajax各自的优缺点,以及在使用中如何取舍

  • 于Flash来说flash是个处理多媒体,矢量图形以及访问机器等;但是对于CSS,文本处理有不足,不容易被搜索;
  • 于Ajax来说AjaxCSS,文本处理有很好的支持,亦支持搜索;但是对多媒体,矢量图形以及访问机器等不足;

共同点

  • 与服务器的无刷新传递消息;
  • 可以检测用户的离线和在线状态;
  • 可以操作DOM

20. Cookie在客户机上是如何存储的

cookies是服务器暂时放在我们电脑里的文本文件,好让服务器来辨认我们的计算机。

当我们在浏览网站的时候,web服务器会先发送小部分资料放在我们的计算机中,cookies会帮助我们,将我们在网站上打印的文字或一些选择记录下来,当我们再次访问同一个网站,web服务器会先检查有没有它上次留下的cookies资料。

若有,会依据cookies里面的内容来判断使用者,从而给我们推出相应的网页内容。

🚚...................................................ᴅᴜᴅᴜ!

21. 🤨什么是Json

  • json是一种轻量级的数据交换格式;
  • 独立于语言平台,解析器和库支持许多不同的编程语言;
  • 它的语法表示三种类型值:简单值(numberstringbooleannull),数组,对象;

22. 线程与进程的区别

一个程序至少有一个进程,一个进程至少有一个线程。线程的划分尺度小于进程,使得多线程程序的并发性高。这里我们可以简单的把进程理解成火车,线程理解为车厢

区别

  • 线程在进程下运行,不能单独运行(单纯的一节节车厢无法运行);
  • 一个进程可以包含多个线程(一辆火车有很多车厢);
  • 不同进程之间的数据难以共享(列车在行驶时,乘客很难从一列火车换到另一列火车);
  • 同一进程下的线程数据共享便捷(乘客在同一列火车上从一节车厢换到另一节很方便);
  • 进程要比线程花费更多的计算机资源(车厢仅仅是跑,或者还要发动动力带它跑,花的力气更多);
  • 进程之间互不影响,但是同一个进程中要是有一个线程出现问题将导致整个进程有问题(一辆类车要是某一节车厢出问题比如起火,会导致火车暂停);
  • 进程可以拓展到多机,而线程最多扩展到多核cpu。(不同的火车可以开在不同的轨道上,而同一火车的车厢只能形式在当前火车行驶的轨道上);
  • 进程使用的内存地址可以上锁,即一个线程使用某些共享内存时,其他线程必须等它结束才能使用这块内存。(例如使用火车上的洗手间-“互斥锁”);
  • 进程使用的内存地址可以限定使用量(例如火车上的卧铺,最多只允许多少个人睡,如果安排满了就需要等待,待有空床位出来了才能进去--“信号量”);

23. 如果网页内容需要支持多语言,需要考虑些什么

  • 应用字符集的选择,选择utf-8编码;
  • 语言书写习惯以及导航结构;
  • 数据库驱动型网站;

24. JavaScrip的一些编写原则

  • 不要再同一行声明多个变量;
  • 使用 ===!== 来做比较;
  • 使用字面量的方式来创建数组、对象,来代替new Array这种形式;
  • switch语句必须要带default分支;
  • fon-in循环中的变量,用var关键字说明作用域,防止变量污染;
  • 尽可能的用三元表达式代替if..else..条件语句;
  • 比较数据类型以下6中情况是falsefalse""0nullundefinedNaN;其余的都是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. 宏任务和微任务

  • 宏任务: 当前调用栈中执行的任务称为宏任务。包括整体代码scriptsetTimeoutsetInterval
  • 微任务: 当前(此次事件循环中)宏任务执行完,在下一个宏任务开始之前需要执行的任务为微任务。包含回调事件,Promiseprocess.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:网关超时,服务器作为网关或代理。但是没有及时从上游服务器收到请求;
  • 505HTTP版本不支持,服务器不支持请求中所用的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文件。建议单独写成文件,有利于结构和行为分离,利于维护;
  • 跨平台性,在绝大多数浏览器支持下,可以在多种平台下运行,例如windowslinux等;

33. DOM和BOM是什么

首先我们需要知道:javascript是由ECMAScript,DOM,BOM三部分构成的

  • ECMAScript是一种语言,是对规定的语法,操作,关键字,语句的一个描述,javascript实现了ECMAScript;
  • DOM是文档对象模型,包括了获取元素,修改样式以及操作元素等三方面的内容,也是通常我们用的最多的操作,其提供了很多兼容性的写法;
  • BOM是浏览器对象模型,包括浏览器的一些操作,window.onload, window.open等还有浏览器时间,监听窗口的改变onresize,监听滚动事件onscroll等;

34. 如何实现多个标签之间的通信

  • 调用 localStorage

(1)、在一个标签内使用localStoragesetItem(key, value)添加(删除或修改)内容;

(2)、在另一个标签页面监听storage事件;

(3)、得到localStorage存储的值,即可实现不用页面之间的通信。

  • 调用 cookie+setInterval()

(1)、将要传递的信息存储在cookie中,可以设置定时读取cookie的信息,即可随时获取想要传递的信息。

  • 使用 Webworker

(1)、webworker作为浏览器的一个新特性,可以提供一个额外的线程来执行一些js代码,并且对浏览器用户界面不影响;

(2)、普通的Webworkernew 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中有几种定时器以及其如何工作

定时器用于在设定的时间执行一段代码,或者在给定的时间间隔内重复该代码。通过函数setTimeoutsetIntervalclearInterval来完成。

  • setTimeoutfunctiondelay)函数用于移动在所述延迟之后调用特定功能的定时器;
  • setIntervalfunctiondelay)函数用于在提到的延迟中重复执行给定的功能,只有在取消时才能停止;
  • clearIntervalid)函数指示定时器停止;

🌈🌈注意: 定时器在一个线程内运行,因此事件可能需要排队等待执行;

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/offsetHeightcontent宽/高 + padding宽/高 + border宽/高);
  • clientWidth/clientHeight (content宽/高 + padding宽/高);

57. 几种减低页面加载时间的方法

  • 压缩CSSJS文件;
  • 合并CSSJS文件,减少http请求;
  • 外部JSCSS放在最底层;
  • 减少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-ageETag的组合;
  • max-age
  • max-ageLast-Modified(If-Modified-Since)的组合;

拓展

在此,拓展一下有关强制缓存(200)和协商缓存(304)部分的内容。

  • 强制缓存(也称强缓存),指当浏览器去请求某个文件的时候,服务端就在respone header里面对该文件做了缓存配置。强制缓存不会向服务器发送请求,直接从缓存中读取资源,在chrome控制台的network选项中可以看到该请求返回200的状态码;
  • 协商缓存:强制缓存给资源设置了过期时间,在未过期时,可以说是给用户自给自足用的。但是当资源过期时,就需要去请求服务器,这时候请求服务器的过程就可以设置成协商缓存。协商缓存就是需要客户端和服务端进行交互的。协商缓存将缓存信息中的EtagLast-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-ModifyLast-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;
  • postMessageHTML5中的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

浏览器端异步和服务器端同步的模块化编程规范。

CommonJSNodeJS,webpackCommonJS规范的主要实践者,它有四个重要的环境变量为模块化的实现提供支持:moduleexportsrequireglobal。实际使用时,用module.exports定义当前模块对外输出的接口(不推荐直接用exports),用require加载模块。

CommonJS用同步的方式加载模块。在服务端,模块文件都存放在本地磁盘,读取非常快,所以这样做不会有问题。但是在浏览器端,限于网络原因,更合理的方案是使用异步加载。

`exports``module.export`区别:

`exports`:对于本身来讲是一个变量(对象),它不是`module`的引用,它是`{}`的引用,它指向`module.exports``{}`模块。只能使用`.`语法 向外暴露变量。

`module.exports``module`是一个变量,指向一块内存,`exports``module`中的一个属性,存储在内存中,然后`exports`属性指向`{}`模块。既可以使用`.`语法,也可以使用`=`直接赋值。

AMD和require.jsAMD规范采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。一般用于客户端。

CMD和sea.jsCMD是另一种js模块化方案,它与AMD很类似,不同点在于:AMD推崇依赖前置、提前执行,CMD推崇依赖就近、延迟执行

*ES6: ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,旨在成为浏览器和服务器通用的模块解决方案。其模块功能主要由两个命令构成:exportimportexport命令用于规定模块的对外接口,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')
}
  • undeclaredundeclared 是一种语法错误,不是数据类型,是未声明也未赋值的变量。

🌈🌈注意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部分的整理,就先整理到这里吧,后继会持续更新。有关开发性能优化篇小编还在整理当中,但是由于最近项目压身,可能会延迟一丢丢吧(生活不易且珍惜🌻🌻)。

整理的过程中,难免会有疏漏,若是看到有误或者需要补充的知识点,欢迎留言小编💌💌。