关于前端:这样回答前端面试题才能拿到offer

36次阅读

共计 11642 个字符,预计需要花费 30 分钟才能阅读完成。

代码输入后果

Promise.resolve(1)
  .then(res => {console.log(res);
    return 2;
  })
  .catch(err => {return 3;})
  .then(res => {console.log(res);
  });

输入后果如下:

1   
2

Promise 是能够链式调用的,因为每次调用 .then 或者 .catch 都会返回一个新的 promise,从而实现了链式调用, 它并不像个别工作的链式调用一样 return this。

下面的输入后果之所以顺次打印出 1 和 2,是因为 resolve(1) 之后走的是第一个 then 办法,并没有进 catch 里,所以第二个 then 中的 res 失去的实际上是第一个 then 的返回值。并且 return 2 会被包装成resolve(2),被最初的 then 打印输出 2。

常见的浏览器内核比拟

  • Trident: 这种浏览器内核是 IE 浏览器用的内核,因为在晚期 IE 占有大量的市场份额,所以这种内核比拟风行,以前有很多网页也是依据这个内核的规范来编写的,然而实际上这个内核对真正的网页规范反对不是很好。然而因为 IE 的高市场占有率,微软也很长时间没有更新 Trident 内核,就导致了 Trident 内核和 W3C 规范脱节。还有就是 Trident 内核的大量 Bug 等平安问题没有失去解决,加上一些专家学者公开本人认为 IE 浏览器不平安的观点,使很多用户开始转向其余浏览器。
  • Gecko: 这是 Firefox 和 Flock 所采纳的内核,这个内核的长处就是功能强大、丰盛,能够反对很多简单网页成果和浏览器扩大接口,然而代价是也不言而喻就是要耗费很多的资源,比方内存。
  • Presto: Opera 已经采纳的就是 Presto 内核,Presto 内核被称为公认的浏览网页速度最快的内核,这得益于它在开发时的天生劣势,在解决 JS 脚本等脚本语言时,会比其余的内核快 3 倍左右,毛病就是为了达到很快的速度而丢掉了一部分网页兼容性。
  • Webkit: Webkit 是 Safari 采纳的内核,它的长处就是网页浏览速度较快,尽管不迭 Presto 然而也胜于 Gecko 和 Trident,毛病是对于网页代码的容错性不高,也就是说对网页代码的兼容性较低,会使一些编写不规范的网页无奈正确显示。WebKit 前身是 KDE 小组的 KHTML 引擎,能够说 WebKit 是 KHTML 的一个开源的分支。
  • Blink: 谷歌在 Chromium Blog 上发表博客,称将与苹果的开源浏览器外围 Webkit 各奔前程,在 Chromium 我的项目中研发 Blink 渲染引擎(即浏览器外围),内置于 Chrome 浏览器之中。其实 Blink 引擎就是 Webkit 的一个分支,就像 webkit 是 KHTML 的分支一样。Blink 引擎当初是谷歌公司与 Opera Software 独特研发,下面提到过的,Opera 弃用了本人的 Presto 内核,退出 Google 营垒,追随谷歌一起研发 Blink。

JavaScript 有哪些数据类型,它们的区别?

JavaScript 共有八种数据类型,别离是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。

其中 Symbol 和 BigInt 是 ES6 中新增的数据类型:

  • Symbol 代表创立后举世无双且不可变的数据类型,它次要是为了解决可能呈现的全局变量抵触的问题。
  • BigInt 是一种数字类型的数据,它能够示意任意精度格局的整数,应用 BigInt 能够平安地存储和操作大整数,即便这个数曾经超出了 Number 可能示意的平安整数范畴。

这些数据能够分为原始数据类型和援用数据类型:

  • 栈:原始数据类型(Undefined、Null、Boolean、Number、String)
  • 堆:援用数据类型(对象、数组和函数)

两种类型的区别在于 存储地位的不同:

  • 原始数据类型间接存储在栈(stack)中的简略数据段,占据空间小、大小固定,属于被频繁应用数据,所以放入栈中存储;
  • 援用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;援用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找援用值时,会首先检索其在栈中的地址,获得地址后从堆中取得实体。

堆和栈的概念存在于数据结构和操作系统内存中,在数据结构中:

  • 在数据结构中,栈中数据的存取形式为先进后出。
  • 堆是一个优先队列,是按优先级来进行排序的,优先级能够依照大小来规定。

在操作系统中,内存被分为栈区和堆区:

  • 栈区内存由编译器主动调配开释,寄存函数的参数值,局部变量的值等。其操作形式相似于数据结构中的栈。
  • 堆区内存个别由开发着调配开释,若开发者不开释,程序完结时可能由垃圾回收机制回收。

对浏览器的了解

浏览器的次要性能是将用户抉择的 web 资源出现进去,它须要从服务器申请资源,并将其显示在浏览器窗口中,资源的格局通常是 HTML,也包含 PDF、image 及其他格局。用户用 URI(Uniform Resource Identifier 对立资源标识符)来指定所申请资源的地位。

HTML 和 CSS 标准中规定了浏览器解释 html 文档的形式,由 W3C 组织对这些标准进行保护,W3C 是负责制订 web 规范的组织。然而浏览器厂商纷纷开发本人的扩大,对标准的遵循并不欠缺,这为 web 开发者带来了重大的兼容性问题。

浏览器能够分为两局部,shell 和 内核。其中 shell 的品种绝对比拟多,内核则比拟少。也有一些浏览器并不辨别外壳和内核。从 Mozilla 将 Gecko 独立进去后,才有了外壳和内核的明确划分。

  • shell 是指浏览器的外壳:例如菜单,工具栏等。次要是提供给用户界面操作,参数设置等等。它是调用内核来实现各种性能的。
  • 内核是浏览器的外围。内核是基于标记语言显示内容的程序或模块。

Number() 的存储空间是多大?如果后盾发送了一个超过最大本人的数字怎么办

Math.pow(2, 53),53 为有效数字,会产生截断,等于 JS 能反对的最大数字。

JS 隐式转换,显示转换

个别非根底类型进行转换时会先调用 valueOf,如果 valueOf 无奈返回根本类型值,就会调用 toString

字符串和数字

  • “+” 操作符,如果有一个为字符串,那么都转化到字符串而后执行字符串拼接
  • “-” 操作符,转换为数字,相减 (-a, a * 1 a/1) 都能进行隐式强制类型转换
[] + {} 和 {} + []

布尔值到数字

  • 1 + true = 2
  • 1 + false = 1

转换为布尔值

  • for 中第二个
  • while
  • if
  • 三元表达式
  • ||(逻辑或)&&(逻辑与)右边的操作数

符号

  • 不能被转换为数字
  • 能被转换为布尔值(都是 true)
  • 能够被转换成字符串 “Symbol(cool)”

宽松相等和严格相等

宽松相等容许进行强制类型转换,而严格相等不容许

字符串与数字

转换为数字而后比拟

其余类型与布尔类型

  • 先把布尔类型转换为数字,而后持续进行比拟

对象与非对象

  • 执行对象的 ToPrimitive(对象)而后持续进行比拟

假值列表

  • undefined
  • null
  • false
  • +0, -0, NaN
  • “”

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

过程与线程的概念

从实质上说,过程和线程都是 CPU 工作工夫片的一个形容:

  • 过程形容了 CPU 在运行指令及加载和保留上下文所需的工夫,放在利用上来说就代表了一个程序。
  • 线程是过程中的更小单位,形容了执行一段指令所需的工夫。

过程是资源分配的最小单位,线程是 CPU 调度的最小单位。

一个过程就是一个程序的运行实例。具体解释就是,启动一个程序的时候,操作系统会为该程序创立一块内存,用来寄存代码、运行中的数据和一个执行工作的主线程,咱们把这样的一个运行环境叫 过程 过程是运行在虚拟内存上的,虚拟内存是用来解决用户对硬件资源的有限需要和无限的硬件资源之间的矛盾的。从操作系统角度来看,虚拟内存即交换文件;从处理器角度看,虚拟内存即虚拟地址空间。

如果程序很多时,内存可能会不够,操作系统为每个过程提供一套独立的虚拟地址空间,从而使得同一块物理内存在不同的过程中能够对应到不同或雷同的虚拟地址,变相的减少了程序能够应用的内存。

过程和线程之间的关系有以下四个特点:

(1)过程中的任意一线程执行出错,都会导致整个过程的解体。

(2)线程之间共享过程中的数据。

(3)当一个过程敞开之后,操作系统会回收过程所占用的内存, 当一个过程退出时,操作系统会回收该过程所申请的所有资源;即便其中任意线程因为操作不当导致内存透露,当过程退出时,这些内存也会被正确回收。

(4)过程之间的内容互相隔离。 过程隔离就是为了使操作系统中的过程互不烦扰,每一个过程只能拜访本人占有的数据,也就避免出现过程 A 写入数据到过程 B 的状况。正是因为过程之间的数据是严格隔离的,所以一个过程如果解体了,或者挂起了,是不会影响到其余过程的。如果过程之间须要进行数据的通信,这时候,就须要应用用于过程间通信的机制了。

Chrome 浏览器的架构图:从图中能够看出,最新的 Chrome 浏览器包含:

  • 1 个浏览器主过程
  • 1 个 GPU 过程
  • 1 个网络过程
  • 多个渲染过程
  • 多个插件过程

这些过程的性能:

  • 浏览器过程:次要负责界面显示、用户交互、子过程治理,同时提供存储等性能。
  • 渲染过程:外围工作是将 HTML、CSS 和 JavaScript 转换为用户能够与之交互的网页,排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该过程中,默认状况下,Chrome 会为每个 Tab 标签创立一个渲染过程。出于平安思考,渲染过程都是运行在沙箱模式下。
  • GPU 过程:其实,GPU 的应用初衷是为了实现 3D CSS 的成果,只是随后网页、Chrome 的 UI 界面都抉择采纳 GPU 来绘制,这使得 GPU 成为浏览器广泛的需要。最初,Chrome 在其多过程架构上也引入了 GPU 过程。
  • 网络过程:次要负责页面的网络资源加载,之前是作为一个模块运行在浏览器过程外面的,直至最近才独立进去,成为一个独自的过程。
  • 插件过程:次要是负责插件的运行,因插件易解体,所以须要通过插件过程来隔离,以保障插件过程解体不会对浏览器和页面造成影响。

所以,关上一个网页,起码须要四个过程:1 个网络过程、1 个浏览器过程、1 个 GPU 过程以及 1 个渲染过程。如果关上的页面有运行插件的话,还须要再加上 1 个插件过程。

尽管多过程模型晋升了浏览器的稳定性、流畅性和安全性,但同样不可避免地带来了一些问题:

  • 更高的资源占用:因为每个过程都会蕴含公共根底构造的正本(如 JavaScript 运行环境),这就意味着浏览器会耗费更多的内存资源。
  • 更简单的体系架构:浏览器各模块之间耦合性高、扩展性差等问题,会导致当初的架构曾经很难适应新的需要了。

symbol 有什么用途

能够用来示意一个举世无双的变量避免命名抵触。然而面试官问还有吗?我没想出其余的用途就间接答我不晓得了,还能够利用 symbol 不会被惯例的办法(除了 Object.getOwnPropertySymbols 外)遍历到,所以能够用来模仿公有变量。

次要用来提供遍历接口,安排了 symbol.iterator 的对象才能够应用 for···of 循环,能够对立解决数据结构。调用之后回返回一个遍历器对象,蕴含有一个 next 办法,应用 next 办法后有两个返回值 value 和 done 别离示意函数以后执行地位的值和是否遍历结束。

Symbol.for() 能够在全局拜访 symbol

代码输入后果

function foo(something){this.a = something}

var obj1 = {foo: foo}

var obj2 = {}

obj1.foo(2); 
console.log(obj1.a); // 2

obj1.foo.call(obj2, 3);
console.log(obj2.a); // 3

var bar = new obj1.foo(4)
console.log(obj1.a); // 2
console.log(bar.a); // 4

输入后果:2 3 2 4

解析:

  1. 首先执行 obj1.foo(2); 会在 obj 中增加 a 属性,其值为 2。之后执行 obj1.a,a 是右 obj1 调用的,所以 this 指向 obj,打印出 2;
  2. 执行 obj1.foo.call(obj2, 3) 时,会将 foo 的 this 指向 obj2,前面就和下面一样了,所以会打印出 3;
  3. obj1.a 会打印出 2;
  4. 最初就是考查 this 绑定的优先级了,new 绑定是比隐式绑定优先级高,所以会输入 4。

代码输入后果

async function async1 () {await async2();
  console.log('async1');
  return 'async1 success'
}
async function async2 () {return new Promise((resolve, reject) => {console.log('async2')
    reject('error')
  })
}
async1().then(res => console.log(res))

输入后果如下:

async2
Uncaught (in promise) error

能够看到,如果 async 函数中抛出了谬误,就会终止谬误后果,不会持续向下执行。

如果想要让谬误不足之处前面的代码执行,能够应用 catch 来捕捉:

async function async1 () {await Promise.reject('error!!!').catch(e => console.log(e))
  console.log('async1');
  return Promise.resolve('async1 success')
}
async1().then(res => console.log(res))
console.log('script start')

这样的输入后果就是:

script start
error!!!
async1
async1 success

过程和线程的区别

  • 过程能够看做独立利用,线程不能
  • 资源:过程是 cpu 资源分配的最小单位(是能领有资源和独立运行的最小单位);线程是 cpu 调度的最小单位(线程是建设在过程的根底上的一次程序运行单位,一个过程中能够有多个线程)。
  • 通信方面:线程间能够通过间接共享同一过程中的资源,而过程通信须要借助 过程间通信。
  • 调度:过程切换比线程切换的开销要大。线程是 CPU 调度的根本单位,线程的切换不会引起过程切换,但某个过程中的线程切换到另一个过程中的线程时,会引起过程切换。
  • 零碎开销:因为创立或撤销过程时,零碎都要为之调配或回收资源,如内存、I/O 等,其开销远大于创立或撤销线程时的开销。同理,在进行过程切换时,波及以后执行过程 CPU 环境还有各种各样状态的保留及新调度过程状态的设置,而线程切换时只需保留和设置大量寄存器内容,开销较小。

协商缓存和强缓存的区别

(1)强缓存

应用强缓存策略时,如果缓存资源无效,则间接应用缓存资源,不用再向服务器发动申请。

强缓存策略能够通过两种形式来设置,别离是 http 头信息中的 Expires 属性和 Cache-Control 属性。

(1)服务器通过在响应头中增加 Expires 属性,来指定资源的过期工夫。在过期工夫以内,该资源能够被缓存应用,不用再向服务器发送申请。这个工夫是一个相对工夫,它是服务器的工夫,因而可能存在这样的问题,就是客户端的工夫和服务器端的工夫不统一,或者用户能够对客户端工夫进行批改的状况,这样就可能会影响缓存命中的后果。

(2)Expires 是 http1.0 中的形式,因为它的一些毛病,在 HTTP 1.1 中提出了一个新的头部属性就是 Cache-Control 属性,它提供了对资源的缓存的更准确的管制。它有很多不同的值,

Cache-Control可设置的字段:

  • public:设置了该字段值的资源示意能够被任何对象(包含:发送申请的客户端、代理服务器等等)缓存。这个字段值不罕用,个别还是应用 max-age= 来准确管制;
  • private:设置了该字段值的资源只能被用户浏览器缓存,不容许任何代理服务器缓存。在理论开发当中,对于一些含有用户信息的 HTML,通常都要设置这个字段值,防止代理服务器 (CDN) 缓存;
  • no-cache:设置了该字段须要先和服务端确认返回的资源是否产生了变动,如果资源未发生变化,则间接应用缓存好的资源;
  • no-store:设置了该字段示意禁止任何缓存,每次都会向服务端发动新的申请,拉取最新的资源;
  • max-age=:设置缓存的最大有效期,单位为秒;
  • s-maxage=:优先级高于 max-age=,仅实用于共享缓存(CDN),优先级高于 max-age 或者 Expires 头;
  • max-stale[=]:设置了该字段表明客户端违心接管曾经过期的资源,然而不能超过给定的工夫限度。

一般来说只须要设置其中一种形式就能够实现强缓存策略,当两种形式一起应用时,Cache-Control 的优先级要高于 Expires。

no-cache 和 no-store 很容易混同:

  • no-cache 是指先要和服务器确认是否有资源更新,在进行判断。也就是说没有强缓存,然而会有协商缓存;
  • no-store 是指不应用任何缓存,每次申请都间接从服务器获取资源。

(2)协商缓存

如果命中强制缓存,咱们无需发动新的申请,间接应用缓存内容,如果没有命中强制缓存,如果设置了协商缓存,这个时候协商缓存就会发挥作用了。

下面曾经说到了,命中协商缓存的条件有两个:

  • max-age=xxx 过期了
  • 值为no-store

应用协商缓存策略时,会先向服务器发送一个申请,如果资源没有产生批改,则返回一个 304 状态,让浏览器应用本地的缓存正本。如果资源产生了批改,则返回批改后的资源。

协商缓存也能够通过两种形式来设置,别离是 http 头信息中的 EtagLast-Modified 属性。

(1)服务器通过在响应头中增加 Last-Modified 属性来指出资源最初一次批改的工夫,当浏览器下一次发动申请时,会在申请头中增加一个 If-Modified-Since 的属性,属性值为上一次资源返回时的 Last-Modified 的值。当申请发送到服务器后服务器会通过这个属性来和资源的最初一次的批改工夫来进行比拟,以此来判断资源是否做了批改。如果资源没有批改,那么返回 304 状态,让客户端应用本地的缓存。如果资源曾经被批改了,则返回批改后的资源。应用这种办法有一个毛病,就是 Last-Modified 标注的最初批改工夫只能准确到秒级,如果某些文件在 1 秒钟以内,被批改屡次的话,那么文件已将扭转了然而 Last-Modified 却没有扭转,这样会造成缓存命中的不精确。

(2)因为 Last-Modified 的这种可能产生的不准确性,http 中提供了另外一种形式,那就是 Etag 属性。服务器在返回资源的时候,在头信息中增加了 Etag 属性,这个属性是资源生成的惟一标识符,当资源产生扭转的时候,这个值也会产生扭转。在下一次资源申请时,浏览器会在申请头中增加一个 If-None-Match 属性,这个属性的值就是上次返回的资源的 Etag 的值。服务接管到申请后会依据这个值来和资源以后的 Etag 的值来进行比拟,以此来判断资源是否产生扭转,是否须要返回资源。通过这种形式,比 Last-Modified 的形式更加准确。

当 Last-Modified 和 Etag 属性同时呈现的时候,Etag 的优先级更高。应用协商缓存的时候,服务器须要思考负载平衡的问题,因而多个服务器上资源的 Last-Modified 应该保持一致,因为每个服务器上 Etag 的值都不一样,因而在思考负载平衡时,最好不要设置 Etag 属性。

总结:

强缓存策略和协商缓存策略在缓存命中时都会间接应用本地的缓存正本,区别只在于协商缓存会向服务器发送一次申请。它们缓存不命中时,都会向服务器发送申请来获取资源。在理论的缓存机制中,强缓存策略和协商缓存策略是一起单干应用的。浏览器首先会依据申请的信息判断,强缓存是否命中,如果命中则间接应用资源。如果不命中则依据头信息向服务器发动申请,应用协商缓存,如果协商缓存命中的话,则服务器不返回资源,浏览器间接应用本地资源的正本,如果协商缓存不命中,则浏览器返回最新的资源给浏览器。

事件是如何实现的?

基于公布订阅模式,就是在浏览器加载的时候会读取事件相干的代码,然而只有理论等到具体的事件触发的时候才会执行。

比方点击按钮,这是个事件(Event),而负责处理事件的代码段通常被称为事件处理程序(Event Handler),也就是「启动对话框的显示」这个动作。

在 Web 端,咱们常见的就是 DOM 事件:

  • DOM0 级事件,间接在 html 元素上绑定 on-event,比方 onclick,勾销的话,dom.onclick = null,同一个事件只能有一个处理程序,前面的会笼罩后面的。
  • DOM2 级事件,通过 addEventListener 注册事件,通过 removeEventListener 来删除事件,一个事件能够有多个事件处理程序,按程序执行,捕捉事件和冒泡事件
  • DOM3 级事件,减少了事件类型,比方 UI 事件,焦点事件,鼠标事件

对浏览器内核的了解

浏览器内核次要分成两局部:

  • 渲染引擎的职责就是渲染,即在浏览器窗口中显示所申请的内容。默认状况下,渲染引擎能够显示 html、xml 文档及图片,它也能够借助插件显示其余类型数据,例如应用 PDF 阅读器插件,能够显示 PDF 格局。
  • JS 引擎:解析和执行 javascript 来实现网页的动态效果。

最开始渲染引擎和 JS 引擎并没有辨别的很明确,起初 JS 引擎越来越独立,内核就偏向于只指渲染引擎。

代码输入后果

console.log(1);

setTimeout(() => {console.log(2);
  Promise.resolve().then(() => {console.log(3)
  });
});

new Promise((resolve, reject) => {console.log(4)
  resolve(5)
}).then((data) => {console.log(data);
})

setTimeout(() => {console.log(6);
})

console.log(7);

代码输入后果如下:

1
4
7
5
2
3
6

代码执行过程如下:

  1. 首先执行 scrip 代码,打印出 1;
  2. 遇到第一个定时器 setTimeout,将其退出到宏工作队列;
  3. 遇到 Promise,执行外面的同步代码,打印出 4,遇到 resolve,将其退出到微工作队列;
  4. 遇到第二个定时器 setTimeout,将其退出到红工作队列;
  5. 执行 script 代码,打印出 7,至此第一轮执行实现;
  6. 指定微工作队列中的代码,打印出 resolve 的后果:5;
  7. 执行宏工作中的第一个定时器 setTimeout,首先打印出 2,而后遇到 Promise.resolve().then(),将其退出到微工作队列;
  8. 执行完这个宏工作,就开始执行微工作队列,打印出 3;
  9. 继续执行宏工作队列中的第二个定时器,打印出 6。

代码输入后果

function a() {
    var temp = 10;
    function b() {console.log(temp); // 10
    }
    b();}
a();

function a() {
    var temp = 10;
    b();}
function b() {console.log(temp); // 报错 Uncaught ReferenceError: temp is not defined
}
a();

在下面的两段代码中,第一段是能够失常输入,这个应该没啥问题,关键在于第二段代码,它会报错 Uncaught ReferenceError: temp is not defined。这时因为在 b 办法执行时,temp 的值为 undefined。

如何实现浏览器内多个标签页之间的通信?

实现多个标签页之间的通信,实质上都是通过中介者模式来实现的。因为标签页之间没有方法间接通信,因而咱们能够找一个中介者,让标签页和中介者进行通信,而后让这个中介者来进行音讯的转发。通信办法如下:

  • 应用 websocket 协定,因为 websocket 协定能够实现服务器推送,所以服务器就能够用来当做这个中介者。标签页通过向服务器发送数据,而后由服务器向其余标签页推送转发。
  • 应用 ShareWorker 的形式,shareWorker 会在页面存在的生命周期内创立一个惟一的线程,并且开启多个页面也只会应用同一个线程。这个时候共享线程就能够充当中介者的角色。标签页间通过共享一个线程,而后通过这个共享的线程来实现数据的替换。
  • 应用 localStorage 的形式,咱们能够在一个标签页对 localStorage 的变动事件进行监听,而后当另一个标签页批改数据的时候,咱们就能够通过这个监听事件来获取到数据。这个时候 localStorage 对象就是充当的中介者的角色。
  • 应用 postMessage 办法,如果咱们可能取得对应标签页的援用,就能够应用 postMessage 办法,进行通信。

常见浏览器所用内核

(1)IE 浏览器内核:Trident 内核,也是俗称的 IE 内核;

(2)Chrome 浏览器内核:统称为 Chromium 内核或 Chrome 内核,以前是 Webkit 内核,当初是 Blink 内核;

(3)Firefox 浏览器内核:Gecko 内核,俗称 Firefox 内核;

(4)Safari 浏览器内核:Webkit 内核;

(5)Opera 浏览器内核:最后是本人的 Presto 内核,起初退出谷歌大军,从 Webkit 又到了 Blink 内核;

(6)360 浏览器、猎豹浏览器内核:IE + Chrome 双内核;

(7)搜狗、漫游、QQ 浏览器内核:Trident(兼容模式)+ Webkit(高速模式);

(8)百度浏览器、世界之窗内核:IE 内核;

(9)2345 浏览器内核:如同以前是 IE 内核,当初也是 IE + Chrome 双内核了;

(10)UC 浏览器内核:这个众口不一,UC 说是他们本人研发的 U3 内核,但如同还是基于 Webkit 和 Trident,还有说是基于火狐内核。

浏览器资源缓存的地位有哪些?

资源缓存的地位一共有 3 种,按优先级从高到低别离是:

  1. Service Worker:Service Worker 运行在 JavaScript 主线程之外,尽管因为脱离了浏览器窗体无奈间接拜访 DOM,然而它能够实现离线缓存、音讯推送、网络代理等性能。它能够让咱们 自在管制 缓存哪些文件、如何匹配缓存、如何读取缓存,并且 缓存是持续性的 。当 Service Worker 没有命中缓存的时候,须要去调用 fetch 函数获取 数据。也就是说,如果没有在 Service Worker 命中缓存,会依据缓存查找优先级去查找数据。 然而不论是从 Memory Cache 中还是从网络申请中获取的数据,浏览器都会显示是从 Service Worker 中获取的内容。
  2. Memory Cache: Memory Cache 就是内存缓存,它的效率最快,然而内存缓存尽管读取高效,可是缓存持续性很短,会随着过程的开释而开释。一旦咱们敞开 Tab 页面,内存中的缓存也就被开释了。
  3. Disk Cache: Disk Cache 也就是存储在硬盘中的缓存,读取速度慢点,然而什么都能存储到磁盘中,比之 Memory Cache 胜在容量和存储时效性上。在所有浏览器缓存中,Disk Cache 覆盖面根本是最大的。它会依据 HTTP Herder 中的字段判断哪些资源须要缓存,哪些资源能够不申请间接应用,哪些资源曾经过期须要从新申请。并且即便在跨站点的状况下,雷同地址的资源一旦被硬盘缓存下来,就不会再次去申请数据。

Disk Cache: Push Cache 是 HTTP/2 中的内容,当以上三种缓存都没有命中时,它才会被应用。并且缓存工夫也很短暂,只在会话(Session)中存在,一旦会话完结就被开释。其具备以下特点:

  • 所有的资源都能被推送,然而 Edge 和 Safari 浏览器兼容性不怎么好
  • 能够推送 no-cacheno-store 的资源
  • 一旦连贯被敞开,Push Cache 就被开释
  • 多个页面能够应用雷同的 HTTP/2 连贯,也就是说能应用同样的缓存
  • Push Cache 中的缓存只能被应用一次
  • 浏览器能够拒绝接受曾经存在的资源推送
  • 能够给其余域名推送资源

代码输入后果

var a = 1;
function printA(){console.log(this.a);
}
var obj={
  a:2,
  foo:printA,
  bar:function(){printA();
  }
}

obj.foo(); // 2
obj.bar(); // 1
var foo = obj.foo;
foo(); // 1

输入后果:2 1 1

解析:

  1. obj.foo(),foo 的 this 指向 obj 对象,所以 a 会输入 2;
  2. obj.bar(),printA 在 bar 办法中执行,所以此时 printA 的 this 指向的是 window,所以会输入 1;
  3. foo(),foo 是在全局对象中执行的,所以其 this 指向的是 window,所以会输入 1;

正文完
 0