乐趣区

关于前端:滴滴前端二面面试题

HTTP 申请报文的是什么样的?

申请报⽂有 4 局部组成:

  • 申请⾏
  • 申请头部
  • 空⾏
  • 申请体

    其中:(1)申请⾏包含:申请⽅法字段、URL 字段、HTTP 协定版本字段。它们⽤空格分隔。例如,GET /index.html HTTP/1.1。
    (2)申请头部: 申请头部由关键字 / 值对组成,每⾏⼀对,关键字和值⽤英⽂冒号“:”分隔

  • User-Agent:产⽣申请的浏览器类型。
  • Accept:客户端可辨认的内容类型列表。
  • Host:申请的主机名,容许多个域名同处⼀个 IP 地址,即虚拟主机。

(3)申请体: post put 等申请携带的数据

JSONP

JSONP 外围原理:script 标签不受同源策略束缚,所以能够用来进行跨域申请,长处是兼容性好,然而只能用于 GET 申请;

const jsonp = ({url, params, callbackName}) => {const generateUrl = () => {
        let dataSrc = ''
        for (let key in params) {if (params.hasOwnProperty(key)) {dataSrc += `${key}=${params[key]}&`
            }
        }
        dataSrc += `callback=${callbackName}`
        return `${url}?${dataSrc}`
    }
    return new Promise((resolve, reject) => {const scriptEle = document.createElement('script')
        scriptEle.src = generateUrl()
        document.body.appendChild(scriptEle)
        window[callbackName] = data => {resolve(data)
            document.removeChild(scriptEle)
        }
    })
}

事件流传机制(事件流)

冒泡和捕捉

什么是 HTTPS 协定?

超文本传输平安协定(Hypertext Transfer Protocol Secure,简称:HTTPS)是一种通过计算机网络进行平安通信的传输协定。HTTPS 经由 HTTP 进行通信,利用 SSL/TLS 来加密数据包。HTTPS 的次要目标是提供对网站服务器的身份认证,爱护替换数据的隐衷与完整性。HTTP 协定采纳 明文传输 信息,存在 信息窃听 信息篡改 信息劫持 的危险,而协定 TLS/SSL 具备 身份验证 信息加密 完整性校验 的性能,能够防止此类问题产生。

平安层的主要职责就是 对发动的 HTTP 申请的数据进行加密操作 对接管到的 HTTP 的内容进行解密操作

伪元素和伪类的区别和作用?

  • 伪元素:在内容元素的前后插入额定的元素或款式,然而这些元素实际上并不在文档中生成。它们只在内部显示可见,但不会在文档的源代码中找到它们,因而,称为“伪”元素。例如:
p::before {content:"第一章:";}
p::after {content:"Hot!";}
p::first-line {background:red;}
p::first-letter {font-size:30px;}
  • 伪类:将非凡的成果增加到特定选择器上。它是已有元素上增加类别的,不会产生新的元素。例如:
a:hover {color: #FF00FF}
p:first-child {color: red}

总结: 伪类是通过在元素选择器上加⼊伪类扭转元素状态,⽽伪元素通过对元素的操作进⾏对元素的扭转。

setTimeout 模仿 setInterval

形容 :应用setTimeout 模仿实现 setInterval 的性能。

实现

const mySetInterval(fn, time) {
    let timer = null;
    const interval = () => {timer = setTimeout(() => {fn();  // time 工夫之后会执行真正的函数 fn
            interval();  // 同时再次调用 interval 自身}, time)
    }
    interval();  // 开始执行
    // 返回用于敞开定时器的函数
    return () => clearTimeout(timer);
}

// 测试
const cancel = mySetInterval(() => console.log(1), 400);
setTimeout(() => {cancel();
}, 1000);  
// 打印两次 1

行内元素有哪些?块级元素有哪些?空 (void) 元素有那些?

  • 行内元素有:a b span img input select strong
  • 块级元素有:div ul ol li dl dt dd h1 h2 h3 h4 h5 h6 p

空元素,即没有内容的 HTML 元素。空元素是在开始标签中敞开的,也就是空元素没有闭合标签:

  • 常见的有:<br><hr><img><input><link><meta>
  • 鲜见的有:<area><base><col><colgroup><command><embed><keygen><param><source><track><wbr>

说一下你对盒模型的了解?

CSS3 中的盒模型有以下两种: 规范盒模型、IE 盒模型
盒模型都是由四个局部组成的, 别离是 margin、border、padding 和 content
规范盒模型和 IE 盒模型的区别在于设置 width 和 height 时, 所对应的范畴不同
1、规范盒模型的 width 和 height 属性的范畴只蕴含了 content
2、IE 盒模型的 width 和 height 属性的范畴蕴含了 border、padding 和 content
能够通过批改元素的 box-sizing 属性来扭转元素的盒模型;1、box-sizing:content-box 示意规范盒模型(默认值)2、box-sizing:border-box 示意 IE 盒模型(怪异盒模型)

公布订阅模式

题目形容: 实现一个公布订阅模式领有 on emit once off 办法

实现代码如下:

class EventEmitter {constructor() {this.events = {};
  }
  // 实现订阅
  on(type, callBack) {if (!this.events[type]) {this.events[type] = [callBack];
    } else {this.events[type].push(callBack);
    }
  }
  // 删除订阅
  off(type, callBack) {if (!this.events[type]) return;
    this.events[type] = this.events[type].filter((item) => {return item !== callBack;});
  }
  // 只执行一次订阅事件
  once(type, callBack) {function fn() {callBack();
      this.off(type, fn);
    }
    this.on(type, fn);
  }
  // 触发事件
  emit(type, ...rest) {this.events[type] &&
      this.events[type].forEach((fn) => fn.apply(this, rest));
  }
}
// 应用如下
// const event = new EventEmitter();

// const handle = (...rest) => {//   console.log(rest);
// };

// event.on("click", handle);

// event.emit("click", 1, 2, 3, 4);

// event.off("click", handle);

// event.emit("click", 1, 2);

// event.once("dbClick", () => {//   console.log(123456);
// });
// event.emit("dbClick");
// event.emit("dbClick");

闭包的利用场景

  • 柯里化 bind
  • 模块

let 闭包

let 会产生临时性死区,在以后的执行上下文中,会进行变量晋升,然而未被初始化,所以在执行上下文执行阶段,执行代码如果还没有执行到变量赋值,就援用此变量就会报错,此变量未初始化。

TCP 的流量管制机制

一般来说,流量管制就是为了让发送方发送数据的速度不要太快,要让接管方来得及接管。TCP 采纳大小可变的 滑动窗口 进行流量管制,窗口大小的单位是字节。这里说的窗口大小其实就是每次传输的数据大小。

  • 当一个连贯建设时,连贯的每一端调配一个缓冲区来保留输出的数据,并将缓冲区的大小发送给另一端。
  • 当数据达到时,接管方发送确认,其中蕴含了本人残余的缓冲区大小。(残余的缓冲区空间的大小被称为窗口,指出窗口大小的告诉称为窗口通告。接管方在发送的每一确认中都含有一个窗口通告。)
  • 如果接管方应用程序读数据的速度可能与数据达到的速度一样快,接管方将在每一确认中发送一个正的窗口通告。
  • 如果发送方操作的速度快于接管方,接管到的数据最终将充斥接管方的缓冲区,导致接管方通告一个零窗口。发送方收到一个零窗口通告时,必须进行发送,直到接管方从新通告一个正的窗口。

对 this 对象的了解

this 是执行上下文中的一个属性,它指向最初一次调用这个办法的对象。在理论开发中,this 的指向能够通过四种调用模式来判断。

  • 第一种是 函数调用模式,当一个函数不是一个对象的属性时,间接作为函数来调用时,this 指向全局对象。
  • 第二种是 办法调用模式,如果一个函数作为一个对象的办法来调用时,this 指向这个对象。
  • 第三种是 结构器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。
  • 第四种是 apply、call 和 bind 调用模式,这三个办法都能够显示的指定调用函数的 this 指向。其中 apply 办法接管两个参数:一个是 this 绑定的对象,一个是参数数组。call 办法接管的参数,第一个是 this 绑定的对象,前面的其余参数是传入函数执行的参数。也就是说,在应用 call() 办法时,传递给函数的参数必须一一列举进去。bind 办法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。这个函数的 this 指向除了应用 new 时会被扭转,其余状况下都不会扭转。

这四种形式,应用结构器调用模式的优先级最高,而后是 apply、call 和 bind 调用模式,而后是办法调用模式,而后是函数调用模式。

代码输入后果

function SuperType(){this.property = true;}

SuperType.prototype.getSuperValue = function(){return this.property;};

function SubType(){this.subproperty = false;}

SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){return this.subproperty;};

var instance = new SubType();
console.log(instance.getSuperValue());

输入后果:true

实际上,这段代码就是在实现原型链继承,SubType 继承了 SuperType,实质是重写了 SubType 的原型对象,代之以一个新类型的实例。SubType 的原型被重写了,所以 instance.constructor 指向的是 SuperType。具体如下:

什么是 DOM 和 BOM?

  • DOM 指的是文档对象模型,它指的是把文档当做一个对象,这个对象次要定义了解决网页内容的办法和接口。
  • BOM 指的是浏览器对象模型,它指的是把浏览器当做一个对象来看待,这个对象次要定义了与浏览器进行交互的法和接口。BOM 的外围是 window,而 window 对象具备双重角色,它既是通过 js 拜访浏览器窗口的一个接口,又是一个 Global(全局)对象。这意味着在网页中定义的任何对象,变量和函数,都作为全局对象的一个属性或者办法存在。window 对象含有 location 对象、navigator 对象、screen 对象等子对象,并且 DOM 的最基本的对象 document 对象也是 BOM 的 window 对象的子对象。

懒加载的实现原理

图片的加载是由 src 引起的,当对 src 赋值时,浏览器就会申请图片资源。依据这个原理,咱们应用 HTML5 的 data-xxx 属性来贮存图片的门路,在须要加载图片的时候,将 data-xxx 中图片的门路赋值给src,这样就实现了图片的按需加载,即懒加载。

留神:data-xxx 中的 xxx 能够自定义,这里咱们应用 data-src 来定义。

懒加载的实现重点在于确定用户须要加载哪张图片,在浏览器中,可视区域内的资源就是用户须要的资源。所以当图片呈现在可视区域时,获取图片的实在地址并赋值给图片即可。

应用原生 JavaScript 实现懒加载:

知识点:

(1)window.innerHeight 是浏览器可视区的高度

(2)document.body.scrollTop || document.documentElement.scrollTop 是浏览器滚动的过的间隔

(3)imgs.offsetTop 是元素顶部间隔文档顶部的高度(包含滚动条的间隔)

(4)图片加载条件:img.offsetTop < window.innerHeight + document.body.scrollTop;

图示: 代码实现:

<div class="container">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
</div>
<script>
var imgs = document.querySelectorAll('img');
function lozyLoad(){
        var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
        var winHeight= window.innerHeight;
        for(var i=0;i < imgs.length;i++){if(imgs[i].offsetTop < scrollTop + winHeight ){imgs[i].src = imgs[i].getAttribute('data-src');
            }
        }
    }
  window.onscroll = lozyLoad();
</script>

如何对我的项目中的图片进行优化?

  1. 不必图片。很多时候会应用到很多润饰类图片,其实这类润饰图片齐全能够用 CSS 去代替。
  2. 对于挪动端来说,屏幕宽度就那么点,齐全没有必要去加载原图节约带宽。个别图片都用 CDN 加载,能够计算出适配屏幕的宽度,而后去申请相应裁剪好的图片。
  3. 小图应用 base64 格局
  4. 将多个图标文件整合到一张图片中(雪碧图)
  5. 抉择正确的图片格式:

    • 对于可能显示 WebP 格局的浏览器尽量应用 WebP 格局。因为 WebP 格局具备更好的图像数据压缩算法,能带来更小的图片体积,而且领有肉眼辨认无差别的图像品质,毛病就是兼容性并不好
    • 小图应用 PNG,其实对于大部分图标这类图片,齐全能够应用 SVG 代替
    • 照片应用 JPEG

(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,还有说是基于火狐内核。

如何提⾼ webpack 的打包速度?

(1)优化 Loader

对于 Loader 来说,影响打包效率首当其冲必属 Babel 了。因为 Babel 会将代码转为字符串生成 AST,而后对 AST 持续进行转变最初再生成新的代码,我的项目越大,转换代码越多,效率就越低。当然了,这是能够优化的。

首先咱们 优化 Loader 的文件搜寻范畴

module.exports = {
  module: {
    rules: [
      {
        // js 文件才应用 babel
        test: /\.js$/,
        loader: 'babel-loader',
        // 只在 src 文件夹下查找
        include: [resolve('src')],
        // 不会去查找的门路
        exclude: /node_modules/
      }
    ]
  }
}

对于 Babel 来说,心愿只作用在 JS 代码上的,而后 node_modules 中应用的代码都是编译过的,所以齐全没有必要再去解决一遍。

当然这样做还不够,还能够将 Babel 编译过的文件 缓存 起来,下次只须要编译更改过的代码文件即可,这样能够大幅度放慢打包工夫

loader: 'babel-loader?cacheDirectory=true'

(2)HappyPack

受限于 Node 是单线程运行的,所以 Webpack 在打包的过程中也是单线程的,特地是在执行 Loader 的时候,长时间编译的工作很多,这样就会导致期待的状况。

HappyPack 能够将 Loader 的同步执行转换为并行的,这样就能充分利用系统资源来放慢打包效率了

module: {
  loaders: [
    {
      test: /\.js$/,
      include: [resolve('src')],
      exclude: /node_modules/,
      // id 前面的内容对应上面
      loader: 'happypack/loader?id=happybabel'
    }
  ]
},
plugins: [
  new HappyPack({
    id: 'happybabel',
    loaders: ['babel-loader?cacheDirectory'],
    // 开启 4 个线程
    threads: 4
  })
]

(3)DllPlugin

DllPlugin 能够将特定的类库提前打包而后引入。这种形式能够极大的缩小打包类库的次数,只有当类库更新版本才有须要从新打包,并且也实现了将公共代码抽离成独自文件的优化计划。DllPlugin 的应用办法如下:

// 独自配置在一个文件中
// webpack.dll.conf.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
  entry: {
    // 想对立打包的类库
    vendor: ['react']
  },
  output: {path: path.join(__dirname, 'dist'),
    filename: '[name].dll.js',
    library: '[name]-[hash]'
  },
  plugins: [
    new webpack.DllPlugin({
      // name 必须和 output.library 统一
      name: '[name]-[hash]',
      // 该属性须要与 DllReferencePlugin 中统一
      context: __dirname,
      path: path.join(__dirname, 'dist', '[name]-manifest.json')
    })
  ]
}

而后须要执行这个配置文件生成依赖文件,接下来须要应用 DllReferencePlugin 将依赖文件引入我的项目中

// webpack.conf.js
module.exports = {
  // ... 省略其余配置
  plugins: [
    new webpack.DllReferencePlugin({
      context: __dirname,
      // manifest 就是之前打包进去的 json 文件
      manifest: require('./dist/vendor-manifest.json'),
    })
  ]
}

(4)代码压缩

在 Webpack3 中,个别应用 UglifyJS 来压缩代码,然而这个是单线程运行的,为了放慢效率,能够应用 webpack-parallel-uglify-plugin 来并行运行 UglifyJS,从而提高效率。

在 Webpack4 中,不须要以上这些操作了,只须要将 mode 设置为 production 就能够默认开启以上性能。代码压缩也是咱们必做的性能优化计划,当然咱们不止能够压缩 JS 代码,还能够压缩 HTML、CSS 代码,并且在压缩 JS 代码的过程中,咱们还能够通过配置实现比方删除 console.log 这类代码的性能。

(5)其余

能够通过一些小的优化点来放慢打包速度

  • resolve.extensions:用来表明文件后缀列表,默认查找程序是 ['.js', '.json'],如果你的导入文件没有增加后缀就会依照这个程序查找文件。咱们应该尽可能减少后缀列表长度,而后将呈现频率高的后缀排在后面
  • resolve.alias:能够通过别名的形式来映射一个门路,能让 Webpack 更快找到门路
  • module.noParse:如果你确定一个文件下没有其余依赖,就能够应用该属性让 Webpack 不扫描该文件,这种形式对于大型的类库很有帮忙

与缓存相干的 HTTP 申请头有哪些

强缓存:

  • Expires
  • Cache-Control

协商缓存:

  • Etag、If-None-Match
  • Last-Modified、If-Modified-Since

JavaScript 有哪些内置对象

全局的对象(global objects)或称规范内置对象,不要和 “ 全局对象(global object)” 混同。这里说的全局的对象是说在
全局作用域里的对象。全局作用域中的其余对象能够由用户的脚本创立或由宿主程序提供。

规范内置对象的分类:

(1)值属性,这些全局属性返回一个简略值,这些值没有本人的属性和办法。例如 Infinity、NaN、undefined、null 字面量

(2)函数属性,全局函数能够间接调用,不须要在调用时指定所属对象,执行完结后会将后果间接返回给调用者。例如 eval()、parseFloat()、parseInt() 等

(3)根本对象,根本对象是定义或应用其余对象的根底。根本对象包含个别对象、函数对象和谬误对象。例如 Object、Function、Boolean、Symbol、Error 等

(4)数字和日期对象,用来示意数字、日期和执行数学计算的对象。例如 Number、Math、Date

(5)字符串,用来示意和操作字符串的对象。例如 String、RegExp

(6)可索引的汇合对象,这些对象示意依照索引值来排序的数据汇合,包含数组和类型数组,以及类数组构造的对象。例如 Array

(7)应用键的汇合对象,这些汇合对象在存储数据时会应用到键,反对依照插入程序来迭代元素。
例如 Map、Set、WeakMap、WeakSet

(8)矢量汇合,SIMD 矢量汇合中的数据会被组织为一个数据序列。
例如 SIMD 等

(9)结构化数据,这些对象用来示意和操作结构化的缓冲区数据,或应用 JSON 编码的数据。例如 JSON 等

(10)管制形象对象
例如 Promise、Generator 等

(11)反射。例如 Reflect、Proxy

(12)国际化,为了反对多语言解决而退出 ECMAScript 的对象。例如 Intl、Intl.Collator 等

(13)WebAssembly

(14)其余。例如 arguments

总结: js 中的内置对象次要指的是在程序执行前存在全局作用域里的由 js 定义的一些全局值属性、函数和用来实例化其余对象的构造函数对象。个别常常用到的如全局变量值 NaN、undefined,全局函数如 parseInt()、parseFloat() 用来实例化对象的构造函数如 Date、Object 等,还有提供数学计算的单体内置对象如 Math 对象。

函数柯里化

什么叫函数柯里化?其实就是将应用多个参数的函数转换成一系列应用一个参数的函数的技术。还不懂?来举个例子。

function add(a, b, c) {return a + b + c}
add(1, 2, 3)
let addCurry = curry(add)
addCurry(1)(2)(3)

当初就是要实现 curry 这个函数,使函数从一次调用传入多个参数变成屡次调用每次传一个参数。

function curry(fn) {let judge = (...args) => {if (args.length == fn.length) return fn(...args)
        return (...arg) => judge(...args, ...arg)
    }
    return judge
}

手写公布订阅

class EventListener {listeners = {};
    on(name, fn) {(this.listeners[name] || (this.listeners[name] = [])).push(fn)
    }
    once(name, fn) {let tem = (...args) => {this.removeListener(name, fn)
            fn(...args)
        }
        fn.fn = tem
        this.on(name, tem)
    }
    removeListener(name, fn) {if (this.listeners[name]) {this.listeners[name] = this.listeners[name].filter(listener => (listener != fn && listener != fn.fn))
        }
    }
    removeAllListeners(name) {if (name && this.listeners[name]) delete this.listeners[name]
        this.listeners = {}}
    emit(name, ...args) {if (this.listeners[name]) {this.listeners[name].forEach(fn => fn.call(this, ...args))
        }
    }
}

文档申明(Doctype)和 <!Doctype html> 有何作用? 严格模式与混淆模式如何辨别?它们有何意义?

文档申明的作用: 文档申明是为了通知浏览器,以后 HTML 文档应用什么版本的 HTML 来写的,这样浏览器能力依照申明的版本来正确的解析。

的作用:<!doctype html> 的作用就是让浏览器进入规范模式,应用最新的 HTML5 规范来解析渲染页面;如果不写,浏览器就会进入混淆模式,咱们须要防止此类情况产生。

严格模式与混淆模式的辨别:

  • 严格模式 :又称为规范模式,指浏览器依照W3C 规范解析代码;
  • 混淆模式:又称怪异模式、兼容模式,是指浏览器用本人的形式解析代码。混淆模式通常模仿老式浏览器的行为,以避免老站点无奈工作;

辨别 :网页中的DTD,间接影响到应用的是严格模式还是浏览模式,能够说DTD 的应用与这两种形式的区别非亲非故。

  • 如果文档蕴含严格的 DOCTYPE,那么它个别以严格模式出现( 严格 DTD ——严格模式);
  • 蕴含过渡 DTDURIDOCTYPE,也以严格模式出现,但有过渡 DTD 而没有 URI(对立资源标识符,就是申明最初的地址)会导致页面以混淆模式出现(有 URI 的过渡 DTD ——严格模式;没有 URI 的过渡 DTD ——混淆模式);
  • DOCTYPE 不存在或模式不正确会导致文档以混淆模式出现(DTD 不存在或者格局不正确——混淆模式);
  • HTML5 没有 DTD,因而也就没有严格模式与混淆模式的区别,HTML5 有绝对宽松的 法,实现时,曾经尽可能大的实现了向后兼容(HTML5 没有严格和混淆之分)。

总之,严格模式让各个浏览器对立执行一套标准兼容模式保障了旧网站的失常运行。

PWA 应用过吗?serviceWorker 的应用原理是啥?

渐进式网络应用(PWA)是谷歌在 2015 年底提出的概念。基本上算是 web 应用程序,但在外观和感觉上与 原生 app相似。反对 PWA 的网站能够提供脱机工作、推送告诉和设施硬件拜访等性能。

Service Worker是浏览器在后盾独立于网页运行的脚本,它关上了通向不须要网页或用户交互的性能的大门。当初,它们已包含如推送告诉和后盾同步等性能。未来,Service Worker将会反对如定期同步或天文围栏等其余性能。本教程探讨的外围性能是拦挡和解决网络申请,包含通过程序来治理缓存中的响应。

代码输入后果

Promise.reject('err!!!')
  .then((res) => {console.log('success', res)
  }, (err) => {console.log('error', err)
  }).catch(err => {console.log('catch', err)
  })

输入后果如下:

error err!!!

咱们晓得,.then函数中的两个参数:

  • 第一个参数是用来解决 Promise 胜利的函数
  • 第二个则是解决失败的函数

也就是说 Promise.resolve('1') 的值会进入胜利的函数,Promise.reject('2')的值会进入失败的函数。

在这道题中,谬误间接被 then 的第二个参数捕捉了,所以就不会被 catch 捕捉了,输入后果为:error err!!!'

然而,如果是像上面这样:

Promise.resolve()
  .then(function success (res) {throw new Error('error!!!')
  }, function fail1 (err) {console.log('fail1', err)
  }).catch(function fail2 (err) {console.log('fail2', err)
  })

then 的第一参数中抛出了谬误,那么他就不会被第二个参数不活了,而是被前面的 catch 捕捉到。

数组去重

应用 indexOf/includes 实现

function unique(arr) {var res = [];
    for(var i = 0; i < arr.length; i++) {if(res.indexOf(arr[i]) === -1) res.push(arr[i]);
        // if(!res.includes(arr[i])) res.push(arr[i]);
    }
    return res;
}

应用 filter(forEach) + indexOf/includes 实现

// filter
function unique(arr) {var res = arr.filter((value, index) => {
        // 只存第一个呈现的元素
        return arr.indexOf(value) === index;
    });
    return res;
}
// forEach
function unique(arr) {var res = [];
    arr.forEach((value) => {if(!res.includes(value)) res.push(value);
    });
    return res;
}

非 API 版本(原生)实现

function unique(arr) {var res = [];
    for(var i = 0; i < arr.length; i++) {
        var flag = false;
        for(var j = 0; j < res.length; j++) {if(arr[i] === res[j]) {
                flag = true;
                break;
            }
        }
        if(flag === false) res.push(arr[i]);
    }
    return res;
}

ES6 应用 Set + 扩大运算符(…)/Array.from() 实现

function unique(arr) {// return [...new Set(arr)];
    return Array.from(new Set(arr));
}

如何应用 for…of 遍历对象

for…of 是作为 ES6 新增的遍历形式,容许遍历一个含有 iterator 接口的数据结构(数组、对象等)并且返回各项的值,一般的对象用 for..of 遍历是会报错的。

如果须要遍历的对象是类数组对象,用 Array.from 转成数组即可。

var obj = {
    0:'one',
    1:'two',
    length: 2
};
obj = Array.from(obj);
for(var k of obj){console.log(k)
}

如果不是类数组对象,就给对象增加一个 [Symbol.iterator] 属性,并指向一个迭代器即可。

// 办法一:var obj = {
    a:1,
    b:2,
    c:3
};

obj[Symbol.iterator] = function(){var keys = Object.keys(this);
    var count = 0;
    return {next(){if(count<keys.length){return {value: obj[keys[count++]],done:false};
            }else{return {value:undefined,done:true};
            }
        }
    }
};

for(var k of obj){console.log(k);
}


// 办法二
var obj = {
    a:1,
    b:2,
    c:3
};
obj[Symbol.iterator] = function*(){var keys = Object.keys(obj);
    for(var k of keys){yield [k,obj[k]]
    }
};

for(var [k,v] of obj){console.log(k,v);
}

替换元素的概念及计算规定

通过批改某个属性值出现的内容就能够被替换的元素就称为“替换元素”。

替换元素除了内容可替换这一个性以外,还有以下个性:

  • 内容的外观不受页面上的 CSS 的影响:用业余的话讲就是在款式体现在 CSS 作用域之外。如何更改替换元素自身的外观须要相似 appearance 属性,或者浏览器本身裸露的一些款式接口。
  • 有本人的尺寸:在 Web 中,很多替换元素在没有明确尺寸设定的状况下,其默认的尺寸(不包含边框)是 300 像素×150 像素,如
  • 在很多 CSS 属性上有本人的一套体现规定:比拟具备代表性的就是 vertical-align 属性,对于替换元素和非替换元素,vertical-align 属性值的解释是不一样的。比方说 vertical-align 的默认值的 baseline,很简略的属性值,基线之意,被定义为字符 x 的下边缘,而替换元素的基线却被硬生生定义成了元素的下边缘。
  • 所有的替换元素都是内联程度元素:也就是替换元素和替换元素、替换元素和文字都是能够在一行显示的。然而,替换元素默认的 display 值却是不一样的,有的是 inline,有的是 inline-block。

替换元素的尺寸从内而外分为三类:

  • 固有尺寸: 指的是替换内容本来的尺寸。例如,图片、视频作为一个独立文件存在的时候,都是有着本人的宽度和高度的。
  • HTML 尺寸: 只能通过 HTML 原生属性扭转,这些 HTML 原生属性包含的 width 和 height 属性、的 size 属性。
  • CSS 尺寸: 特指能够通过 CSS 的 width 和 height 或者 max-width/min-width 和 max-height/min-height 设置的尺寸,对应盒尺寸中的 content box。

这三层构造的计算规定具体如下:
(1)如果没有 CSS 尺寸和 HTML 尺寸,则应用固有尺寸作为最终的宽高。
(2)如果没有 CSS 尺寸,则应用 HTML 尺寸作为最终的宽高。
(3)如果有 CSS 尺寸,则最终尺寸由 CSS 属性决定。
(4)如果“固有尺寸”含有固有的宽高比例,同时仅设置了宽度或仅设置了高度,则元素仍然依照固有的宽高比例显示。
(5)如果下面的条件都不合乎,则最终宽度体现为 300 像素,高度为 150 像素。
(6)内联替换元素和块级替换元素应用下面同一套尺寸计算规定。

对 keep-alive 的了解

HTTP1.0 中默认是在每次申请 / 应答,客户端和服务器都要新建一个连贯,实现之后立刻断开连接,这就是 短连贯 。当应用 Keep-Alive 模式时,Keep-Alive 性能使客户端到服务器端的连贯继续无效,当呈现对服务器的后继申请时,Keep-Alive 性能防止了建设或者从新建设连贯,这就是 长连贯。其应用办法如下:

  • HTTP1.0 版本是默认没有 Keep-alive 的(也就是默认会发送 keep-alive),所以要想连贯失去放弃,必须手动配置发送 Connection: keep-alive 字段。若想断开 keep-alive 连贯,需发送 Connection:close 字段;
  • HTTP1.1 规定了默认放弃长连贯,数据传输实现了放弃 TCP 连接不断开,期待在同域名下持续用这个通道传输数据。如果须要敞开,须要客户端发送 Connection:close 首部字段。

Keep-Alive 的 建设过程

  • 客户端向服务器在发送申请报文同时在首部增加发送 Connection 字段
  • 服务器收到申请并解决 Connection 字段
  • 服务器回送 Connection:Keep-Alive 字段给客户端
  • 客户端接管到 Connection 字段
  • Keep-Alive 连贯建设胜利

服务端主动断开过程(也就是没有 keep-alive)

  • 客户端向服务器只是发送内容报文(不蕴含 Connection 字段)
  • 服务器收到申请并解决
  • 服务器返回客户端申请的资源并敞开连贯
  • 客户端接管资源,发现没有 Connection 字段,断开连接

客户端申请断开连接过程

  • 客户端向服务器发送 Connection:close 字段
  • 服务器收到申请并解决 connection 字段
  • 服务器回送响应资源并断开连接
  • 客户端接管资源并断开连接

开启 Keep-Alive 的 长处:

  • 较少的 CPU 和内存的使⽤(因为同时关上的连贯的缩小了);
  • 容许申请和应答的 HTTP 管线化;
  • 升高拥塞管制(TCP 连贯缩小了);
  • 缩小了后续申请的提早(⽆需再进⾏握⼿);
  • 报告谬误⽆需敞开 TCP 连;

开启 Keep-Alive 的 毛病

  • 长时间的 Tcp 连贯容易导致系统资源有效占用,节约系统资源。

CDN 的作用

CDN 个别会用来托管 Web 资源(包含文本、图片和脚本等),可供下载的资源(媒体文件、软件、文档等),应用程序(门户网站等)。应用 CDN 来减速这些资源的拜访。

(1)在性能方面,引入 CDN 的作用在于:

  • 用户收到的内容来自最近的数据中心,提早更低,内容加载更快
  • 局部资源申请调配给了 CDN,缩小了服务器的负载

(2)在平安方面,CDN 有助于进攻 DDoS、MITM 等网络攻击:

  • 针对 DDoS:通过监控剖析异样流量,限度其申请频率
  • 针对 MITM:从源服务器到 CDN 节点到 ISP(Internet Service Provider),全链路 HTTPS 通信

除此之外,CDN 作为一种根底的云服务,同样具备资源托管、按需扩大(可能应答流量顶峰)等方面的劣势。

说一下 HTTP 和 HTTPS 协定的区别?

1、HTTPS 协定须要 CA 证书, 费用较高; 而 HTTP 协定不须要
2、HTTP 协定是超文本传输协定, 信息是明文传输的,HTTPS 则是具备安全性的 SSL 加密传输协定;
3、应用不同的连贯形式, 端口也不同,HTTP 协定端口是 80,HTTPS 协定端口是 443;
4、HTTP 协定连贯很简略, 是无状态的;HTTPS 协定是具备 SSL 和 HTTP 协定构建的可进行加密传输、身份认证的网络协议, 比 HTTP 更加平安

说一下 vue3.0 你理解多少?

 <!-- 响应式原理的扭转 Vue3.x 应用 Proxy 取代 Vue2.x 版本的 Object.defineProperty -->
 <!-- 组件选项申明形式 Vue3.x 应用 Composition API setup 是 Vue3.x 新增的一个选项,他
    是组件内应用 Composition API 的入口 -->
 <!-- 模板语法变动 slot 具名插槽语法 自定义指令 v-model 降级 -->
 <!-- 其它方面的更改 Suspense 反对 Fragment(多个根节点) 和 Protal (在 dom 其余局部渲染组建内容)组件
     针对一些非凡的场景做了解决。基于 treeshaking 优化,提供了更多的内置性能。-->

代码输入问题

window.number = 2;
var obj = {
 number: 3,
 db1: (function(){console.log(this);
   this.number *= 4;
   return function(){console.log(this);
     this.number *= 5;
   }
 })()}
var db1 = obj.db1;
db1();
obj.db1();
console.log(obj.number);     // 15
console.log(window.number);  // 40

这道题目看清起来有点乱,然而实际上是考查 this 指向的:

  1. 执行 db1()时,this 指向全局作用域,所以 window.number 4 = 8,而后执行匿名函数,所以 window.number 5 = 40;
  2. 执行 obj.db1(); 时,this 指向 obj 对象,执行匿名函数,所以 obj.numer * 5 = 15。
退出移动版