iframe 有那些长处和毛病?

iframe 元素会创立蕴含另外一个文档的内联框架(即行内框架)。

长处:

  • 用来加载速度较慢的内容(如广告)
  • 能够使脚本能够并行下载
  • 能够实现跨子域通信

毛病:

  • iframe 会阻塞主页面的 onload 事件
  • 无奈被一些搜索引擎索辨认
  • 会产生很多页面,不容易治理

compose

题目形容:实现一个 compose 函数

// 用法如下:function fn1(x) {  return x + 1;}function fn2(x) {  return x + 2;}function fn3(x) {  return x + 3;}function fn4(x) {  return x + 4;}const a = compose(fn1, fn2, fn3, fn4);console.log(a(1)); // 1+4+3+2+1=11

实现代码如下:

function compose(...fn) {  if (!fn.length) return (v) => v;  if (fn.length === 1) return fn[0];  return fn.reduce(    (pre, cur) =>      (...args) =>        pre(cur(...args))  );}

如何防止回流与重绘?

缩小回流与重绘的措施:

  • 操作DOM时,尽量在低层级的DOM节点进行操作
  • 不要应用table布局, 一个小的改变可能会使整个table进行从新布局
  • 应用CSS的表达式
  • 不要频繁操作元素的款式,对于动态页面,能够批改类名,而不是款式。
  • 应用absolute或者fixed,使元素脱离文档流,这样他们发生变化就不会影响其余元素
  • 防止频繁操作DOM,能够创立一个文档片段documentFragment,在它下面利用所有DOM操作,最初再把它增加到文档中
  • 将元素先设置display: none,操作完结后再把它显示进去。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
  • 将DOM的多个读操作(或者写操作)放在一起,而不是读写操作穿插着写。这得益于浏览器的渲染队列机制

浏览器针对页面的回流与重绘,进行了本身的优化——渲染队列

浏览器会将所有的回流、重绘的操作放在一个队列中,当队列中的操作到了肯定的数量或者到了肯定的工夫距离,浏览器就会对队列进行批处理。这样就会让屡次的回流、重绘变成一次回流重绘。

下面,将多个读操作(或者写操作)放在一起,就会等所有的读操作进入队列之后执行,这样,本来应该是触发屡次回流,变成了只触发一次回流。

常见的HTTP申请头和响应头

HTTP Request Header 常见的申请头:

  • Accept:浏览器可能解决的内容类型
  • Accept-Charset:浏览器可能显示的字符集
  • Accept-Encoding:浏览器可能解决的压缩编码
  • Accept-Language:浏览器以后设置的语言
  • Connection:浏览器与服务器之间连贯的类型
  • Cookie:以后页面设置的任何Cookie
  • Host:发出请求的页面所在的域
  • Referer:发出请求的页面的URL
  • User-Agent:浏览器的用户代理字符串

HTTP Responses Header 常见的响应头:

  • Date:示意音讯发送的工夫,工夫的形容格局由rfc822定义
  • server:服务器名称
  • Connection:浏览器与服务器之间连贯的类型
  • Cache-Control:管制HTTP缓存
  • content-type:示意前面的文档属于什么MIME类型

常见的 Content-Type 属性值有以下四种:

(1)application/x-www-form-urlencoded:浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 形式提交数据。该种形式提交的数据放在 body 外面,数据依照 key1=val1&key2=val2 的形式进行编码,key 和 val 都进行了 URL转码。

(2)multipart/form-data:该种形式也是一个常见的 POST 提交形式,通常表单上传文件时应用该种形式。

(3)application/json:服务器音讯主体是序列化后的 JSON 字符串。

(4)text/xml:该种形式次要用来提交 XML 格局的数据。

代码输入后果

f = function() {return true;};   g = function() {return false;};   (function() {      if (g() && [] == ![]) {         f = function f() {return false;};         function g() {return true;}      }   })();   console.log(f());

输入后果: false

这里首先定义了两个变量f和g,咱们晓得变量是能够从新赋值的。前面是一个匿名自执行函数,在 if 条件中调用了函数 g(),因为在匿名函数中,又从新定义了函数g,就笼罩了内部定义的变量g,所以,这里调用的是外部函数 g 办法,返回为 true。第一个条件通过,进入第二个条件。

第二个条件是[] == ![],先看 ![] ,在 JavaScript 中,当用于布尔运算时,比方在这里,对象的非空援用被视为 true,空援用 null 则被视为 false。因为这里不是一个 null, 而是一个没有元素的数组,所以 [] 被视为 true, 而 ![] 的后果就是 false 了。当一个布尔值参加到条件运算的时候,true 会被看作 1, 而 false 会被看作 0。当初条件变成了 [] == 0 的问题了,当一个对象参加条件比拟的时候,它会被求值,求值的后果是数组成为一个字符串,[] 的后果就是 '' ,而 '' 会被当作 0 ,所以,条件成立。

两个条件都成立,所以会执行条件中的代码, f 在定义是没有应用var,所以他是一个全局变量。因而,这里会通过闭包拜访到内部的变量 f, 从新赋值,当初执行 f 函数返回值曾经成为 false 了。而 g 则不会有这个问题,这里是一个函数内定义的 g,不会影响到内部的 g 函数。所以最初的后果就是 false。

new 一个函数产生了什么

结构调用:

  • 发明一个全新的对象
  • 这个对象会被执行 [[Prototype]] 连贯,将这个新对象的 [[Prototype]] 链接到这个构造函数.prototype 所指向的对象
  • 这个新对象会绑定到函数调用的 this
  • 如果函数没有返回其余对象,那么 new 表达式中的函数调用会主动返回这个新对象

<script src=’xxx’ ’xxx’/>内部js文件先加载还是onload先执行,为什么?

onload 是所以加载实现之后执行的

实现一个三角形

CSS绘制三角形次要用到的是border属性,也就是边框。

平时在给盒子设置边框时,往往都设置很窄,就可能误以为边框是由矩形组成的。实际上,border属性是右三角形组成的,上面看一个例子:

div {    width: 0;    height: 0;    border: 100px solid;    border-color: orange blue red green;}

将元素的长宽都设置为0

(1)三角1

div {    width: 0;    height: 0;    border-top: 50px solid red;    border-right: 50px solid transparent;    border-left: 50px solid transparent;}

(2)三角2

div {    width: 0;    height: 0;    border-bottom: 50px solid red;    border-right: 50px solid transparent;    border-left: 50px solid transparent;}

(3)三角3

div {    width: 0;    height: 0;    border-left: 50px solid red;    border-top: 50px solid transparent;    border-bottom: 50px solid transparent;}

(4)三角4

div {    width: 0;    height: 0;    border-right: 50px solid red;    border-top: 50px solid transparent;    border-bottom: 50px solid transparent;}

(5)三角5

div {    width: 0;    height: 0;    border-top: 100px solid red;    border-right: 100px solid transparent;}

还有很多,就不一一实现了,总体的准则就是通过上下左右边框来管制三角形的方向,用边框的宽度比来管制三角形的角度。

类数组转化为数组的办法

题目形容:类数组领有 length 属性 能够应用下标来拜访元素 然而不能应用数组的办法 如何把类数组转化为数组?

实现代码如下:

const arrayLike=document.querySelectorAll('div')// 1.扩大运算符[...arrayLike]// 2.Array.fromArray.from(arrayLike)// 3.Array.prototype.sliceArray.prototype.slice.call(arrayLike)// 4.Array.applyArray.apply(null, arrayLike)// 5.Array.prototype.concatArray.prototype.concat.apply([], arrayLike)

对Promise的了解

Promise是异步编程的一种解决方案,它是一个对象,能够获取异步操作的音讯,他的呈现大大改善了异步编程的窘境,防止了天堂回调,它比传统的解决方案回调函数和事件更正当和更弱小。

所谓Promise,简略说就是一个容器,外面保留着某个将来才会完结的事件(通常是一个异步操作)的后果。从语法上说,Promise 是一个对象,从它能够获取异步操作的音讯。Promise 提供对立的 API,各种异步操作都能够用同样的办法进行解决。

(1)Promise的实例有三个状态:

  • Pending(进行中)
  • Resolved(已实现)
  • Rejected(已回绝)

当把一件事件交给promise时,它的状态就是Pending,工作实现了状态就变成了Resolved、没有实现失败了就变成了Rejected。

(2)Promise的实例有两个过程

  • pending -> fulfilled : Resolved(已实现)
  • pending -> rejected:Rejected(已回绝)

留神:一旦从进行状态变成为其余状态就永远不能更改状态了。

Promise的特点:

  • 对象的状态不受外界影响。promise对象代表一个异步操作,有三种状态,pending(进行中)、fulfilled(已胜利)、rejected(已失败)。只有异步操作的后果,能够决定以后是哪一种状态,任何其余操作都无奈扭转这个状态,这也是promise这个名字的由来——“承诺”;
  • 一旦状态扭转就不会再变,任何时候都能够失去这个后果。promise对象的状态扭转,只有两种可能:从pending变为fulfilled,从pending变为rejected。这时就称为resolved(已定型)。如果扭转曾经产生了,你再对promise对象增加回调函数,也会立刻失去这个后果。这与事件(event)齐全不同,事件的特点是:如果你错过了它,再去监听是得不到后果的。

Promise的毛病:

  • 无奈勾销Promise,一旦新建它就会立刻执行,无奈中途勾销。
  • 如果不设置回调函数,Promise外部抛出的谬误,不会反馈到内部。
  • 当处于pending状态时,无奈得悉目前停顿到哪一个阶段(刚刚开始还是行将实现)。

总结: Promise 对象是异步编程的一种解决方案,最早由社区提出。Promise 是一个构造函数,接管一个函数作为参数,返回一个 Promise 实例。一个 Promise 实例有三种状态,别离是pending、resolved 和 rejected,别离代表了进行中、已胜利和已失败。实例的状态只能由 pending 转变 resolved 或者rejected 状态,并且状态一经扭转,就凝固了,无奈再被扭转了。

状态的扭转是通过 resolve() 和 reject() 函数来实现的,能够在异步操作完结后调用这两个函数扭转 Promise 实例的状态,它的原型上定义了一个 then 办法,应用这个 then 办法能够为两个状态的扭转注册回调函数。这个回调函数属于微工作,会在本轮事件循环的开端执行。

留神: 在结构 Promise 的时候,构造函数外部的代码是立刻执行的

对于原型的继承咱们借助寄生组合继承

function Person(obj) {    this.name = obj.name    this.age = obj.age}Person.prototype.add = function(value){    console.log(value)}var p1 = new Person({name:"番茄", age: 18})function Person1(obj) {    Person.call(this, obj)    this.sex = obj.sex}// 这一步是继承的要害Person1.prototype = Object.create(Person.prototype)Person1.prototype.play = function(value){    console.log(value)}var p2 = new Person1({name:"鸡蛋", age: 118, sex: "男"})

深拷贝浅拷贝

浅拷贝:浅拷贝通过ES6新个性Object.assign()或者通过扩大运算法...来达到浅拷贝的目标,浅拷贝批改正本,不会影响原数据,但毛病是浅拷贝只能拷贝第一层的数据,且都是值类型数据,如果有援用型数据,批改正本会影响原数据。深拷贝:通过利用JSON.parse(JSON.stringify())来实现深拷贝的目标,但利用JSON拷贝也是有毛病的,当要拷贝的数据中含有undefined/function/symbol类型是无奈进行拷贝的,当然咱们想我的项目开发中须要深拷贝的数据个别不会含有以上三种类型,如有须要能够本人在封装一个函数来实现。

常⽤的meta标签有哪些

meta 标签由 namecontent 属性定义,用来形容网页文档的属性,比方网页的作者,网页形容,关键词等,除了HTTP规范固定了一些name作为大家应用的共识,开发者还能够自定义name。

罕用的meta标签:
(1)charset,用来形容HTML文档的编码类型:

<meta charset="UTF-8" >

(2) keywords,页面关键词:

<meta name="keywords" content="关键词" />

(3)description,页面形容:

<meta name="description" content="页面形容内容" />

(4)refresh,页面重定向和刷新:

<meta http-equiv="refresh" content="0;url=" />

(5)viewport,适配挪动端,能够管制视口的大小和比例:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

其中,content 参数有以下几种:

  • width viewport :宽度(数值/device-width)
  • height viewport :高度(数值/device-height)
  • initial-scale :初始缩放比例
  • maximum-scale :最大缩放比例
  • minimum-scale :最小缩放比例
  • user-scalable :是否容许用户缩放(yes/no)

(6)搜索引擎索引形式:

<meta name="robots" content="index,follow" />

其中,content 参数有以下几种:

  • all:文件将被检索,且页面上的链接能够被查问;
  • none:文件将不被检索,且页面上的链接不能够被查问;
  • index:文件将被检索;
  • follow:页面上的链接能够被查问;
  • noindex:文件将不被检索;
  • nofollow:页面上的链接不能够被查问。

CSS预处理器/后处理器是什么?为什么要应用它们?

预处理器, 如:lesssassstylus,用来预编译sass或者less,减少了css代码的复用性。层级,mixin, 变量,循环, 函数等对编写以及开发UI组件都极为不便。

后处理器, 如: postCss,通常是在实现的样式表中依据css标准解决css,让其更加无效。目前最常做的是给css属性增加浏览器公有前缀,实现跨浏览器兼容性的问题。

css预处理器为css减少一些编程个性,无需思考浏览器的兼容问题,能够在CSS中应用变量,简略的逻辑程序,函数等在编程语言中的一些根本的性能,能够让css更加的简洁,减少适应性以及可读性,可维护性等。

其它css预处理器语言:Sass(Scss), Less, Stylus, Turbine, Swithch css, CSS Cacheer, DT Css

应用起因:

  • 构造清晰, 便于扩大
  • 能够很不便的屏蔽浏览器公有语法的差别
  • 能够轻松实现多重继承
  • 完满的兼容了CSS代码,能够利用到老我的项目中

实现模板字符串解析性能

题目形容:

let template = '我是{{name}},年龄{{age}},性别{{sex}}';let data = {  name: '姓名',  age: 18}render(template, data); // 我是姓名,年龄18,性别undefined

实现代码如下:

function render(template, data) {  let computed = template.replace(/\{\{(\w+)\}\}/g, function (match, key) {    return data[key];  });  return computed;}

浏览器渲染优化

(1)针对JavaScript: JavaScript既会阻塞HTML的解析,也会阻塞CSS的解析。因而咱们能够对JavaScript的加载形式进行扭转,来进行优化:

(1)尽量将JavaScript文件放在body的最初

(2) body两头尽量不要写<script>标签

(3)<script>标签的引入资源形式有三种,有一种就是咱们罕用的间接引入,还有两种就是应用 async 属性和 defer 属性来异步引入,两者都是去异步加载内部的JS文件,不会阻塞DOM的解析(尽量应用异步加载)。三者的区别如下:

  • script 立刻进行页面渲染去加载资源文件,当资源加载结束后立刻执行js代码,js代码执行结束后持续渲染页面;
  • async 是在下载实现之后,立刻异步加载,加载好后立刻执行,多个带async属性的标签,不能保障加载的程序;
  • defer 是在下载实现之后,立刻异步加载。加载好后,如果 DOM 树还没构建好,则先等 DOM 树解析好再执行;如果DOM树曾经筹备好,则立刻执行。多个带defer属性的标签,依照程序执行。

(2)针对CSS:应用CSS有三种形式:应用link、@import、内联款式,其中link和@import都是导入内部款式。它们之间的区别:

  • link:浏览器会派发一个新等线程(HTTP线程)去加载资源文件,与此同时GUI渲染线程会持续向下渲染代码
  • @import:GUI渲染线程会临时进行渲染,去服务器加载资源文件,资源文件没有返回之前不会持续渲染(妨碍浏览器渲染)
  • style:GUI间接渲染

内部款式如果长时间没有加载结束,浏览器为了用户体验,会应用浏览器会默认款式,确保首次渲染的速度。所以CSS个别写在headr中,让浏览器尽快发送申请去获取css款式。

所以,在开发过程中,导入内部款式应用link,而不必@import。如果css少,尽可能采纳内嵌款式,间接写在style标签中。

(3)针对DOM树、CSSOM树: 能够通过以下几种形式来缩小渲染的工夫:

  • HTML文件的代码层级尽量不要太深
  • 应用语义化的标签,来防止不规范语义化的非凡解决
  • 缩小CSSD代码的层级,因为选择器是从左向右进行解析的

(4)缩小回流与重绘:

  • 操作DOM时,尽量在低层级的DOM节点进行操作
  • 不要应用table布局, 一个小的改变可能会使整个table进行从新布局
  • 应用CSS的表达式
  • 不要频繁操作元素的款式,对于动态页面,能够批改类名,而不是款式。
  • 应用absolute或者fixed,使元素脱离文档流,这样他们发生变化就不会影响其余元素
  • 防止频繁操作DOM,能够创立一个文档片段documentFragment,在它下面利用所有DOM操作,最初再把它增加到文档中
  • 将元素先设置display: none,操作完结后再把它显示进去。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
  • 将DOM的多个读操作(或者写操作)放在一起,而不是读写操作穿插着写。这得益于浏览器的渲染队列机制

浏览器针对页面的回流与重绘,进行了本身的优化——渲染队列

浏览器会将所有的回流、重绘的操作放在一个队列中,当队列中的操作到了肯定的数量或者到了肯定的工夫距离,浏览器就会对队列进行批处理。这样就会让屡次的回流、重绘变成一次回流重绘。

将多个读操作(或者写操作)放在一起,就会等所有的读操作进入队列之后执行,这样,本来应该是触发屡次回流,变成了只触发一次回流。

对事件循环的了解

因为 js 是单线程运行的,在代码执行时,通过将不同函数的执行上下文压入执行栈中来保障代码的有序执行。在执行同步代码时,如果遇到异步事件,js 引擎并不会始终期待其返回后果,而是会将这个事件挂起,继续执行执行栈中的其余工作。当异步事件执行结束后,再将异步事件对应的回调退出到一个工作队列中期待执行。工作队列能够分为宏工作队列和微工作队列,当以后执行栈中的事件执行结束后,js 引擎首先会判断微工作队列中是否有工作能够执行,如果有就将微工作队首的事件压入栈中执行。当微工作队列中的工作都执行实现后再去执行宏工作队列中的工作。

Event Loop 执行程序如下所示:

  • 首先执行同步代码,这属于宏工作
  • 当执行完所有同步代码后,执行栈为空,查问是否有异步代码须要执行
  • 执行所有微工作
  • 当执行完所有微工作后,如有必要会渲染页面
  • 而后开始下一轮 Event Loop,执行宏工作中的异步代码

CDN的原理

CDN和DNS有着密不可分的分割,先来看一下DNS的解析域名过程,在浏览器输出的解析过程如下:
(1) 查看浏览器缓存
(2)查看操作系统缓存,常见的如hosts文件
(3)查看路由器缓存
(4)如果前几步都没没找到,会向ISP(网络服务提供商)的LDNS服务器查问
(5)如果LDNS服务器没找到,会向根域名服务器(Root Server)申请解析,分为以下几步:

  • 根服务器返回顶级域名(TLD)服务器如.com.cn.org等的地址,该例子中会返回.com的地址
  • 接着向顶级域名服务器发送申请,而后会返回次级域名(SLD)服务器的地址,本例子会返回.test的地址
  • 接着向次级域名服务器发送申请,而后会返回通过域名查问到的指标IP,本例子会返回www.test.com的地址
  • Local DNS Server会缓存后果,并返回给用户,缓存在零碎中

CDN的工作原理: (1)用户未应用CDN缓存资源的过程:

  1. 浏览器通过DNS对域名进行解析(就是下面的DNS解析过程),顺次失去此域名对应的IP地址
  2. 浏览器依据失去的IP地址,向域名的服务主机发送数据申请
  3. 服务器向浏览器返回响应数据

(2)用户应用CDN缓存资源的过程:

  1. 对于点击的数据的URL,通过本地DNS零碎的解析,发现该URL对应的是一个CDN专用的DNS服务器,DNS零碎就会将域名解析权交给CNAME指向的CDN专用的DNS服务器。
  2. CND专用DNS服务器将CND的全局负载平衡设施IP地址返回给用户
  3. 用户向CDN的全局负载平衡设施发动数据申请
  4. CDN的全局负载平衡设施依据用户的IP地址,以及用户申请的内容URL,抉择一台用户所属区域的区域负载平衡设施,通知用户向这台设施发动申请
  5. 区域负载平衡设施抉择一台适合的缓存服务器来提供服务,将该缓存服务器的IP地址返回给全局负载平衡设施
  6. 全局负载平衡设施把服务器的IP地址返回给用户
  7. 用户向该缓存服务器发动申请,缓存服务器响应用户的申请,将用户所需内容发送至用户终端。

如果缓存服务器没有用户想要的内容,那么缓存服务器就会向它的上一级缓存服务器申请内容,以此类推,直到获取到须要的资源。最初如果还是没有,就会回到本人的服务器去获取资源。

CNAME(意为:别名):在域名解析中,实际上解析进去的指定域名对应的IP地址,或者该域名的一个CNAME,而后再依据这个CNAME来查找对应的IP地址。