乐趣区

关于前端:前端高频面试题四附答案

手写公布订阅

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

实现一个 add 办法

题目形容: 实现一个 add 办法 使计算结果可能满足如下预期:
add(1)(2)(3)()=6
add(1,2,3)(4)()=10

其实就是考函数柯里化

实现代码如下:

function add(...args) {let allArgs = [...args];
  function fn(...newArgs) {allArgs = [...allArgs, ...newArgs];
    return fn;
  }
  fn.toString = function () {if (!allArgs.length) {return;}
    return allArgs.reduce((sum, cur) => sum + cur);
  };
  return fn;
}

同步和异步的区别

  • 同步 指的是当一个过程在执行某个申请时,如果这个申请须要期待一段时间能力返回,那么这个过程会始终期待上来,直到音讯返回为止再持续向下执行。
  • 异步 指的是当一个过程在执行某个申请时,如果这个申请须要期待一段时间能力返回,这个时候过程会持续往下执行,不会阻塞期待音讯的返回,当音讯返回时零碎再告诉过程进行解决。

说一下 data 为什么是一个函数而不是一个对象?

JavaScript 中的对象是援用类型的数据,当多个实例援用同一个对象时,只有一个实例对这个对象进行操作,其余实例中的数据也会发生变化。而在 Vue 中,咱们更多的是想要复用组件,那就须要每个组件都有本人的数据,这样组件之间才不会互相烦扰。所以组件的数据不能写成对象的模式,而是要写成函数的模式。数据以函数返回值的模式定义,这样当咱们每次复用组件的时候,就会返回一个新的 data,也就是说每个组件都有本人的公有数据空间,它们各自保护本人的数据,不会烦扰其余组件的失常运行。

CDN 的概念

CDN(Content Delivery Network,内容散发网络)是指一种通过互联网相互连贯的电脑网络零碎,利用最靠近每位用户的服务器,更快、更牢靠地将音乐、图片、视频、应用程序及其他文件发送给用户,来提供高性能、可扩展性及低成本的网络内容传递给用户。

典型的 CDN 零碎由上面三个局部组成:

  • 散发服务零碎: 最根本的工作单元就是 Cache 设施,cache(边缘 cache)负责间接响应最终用户的拜访申请,把缓存在本地的内容疾速地提供给用户。同时 cache 还负责与源站点进行内容同步,把更新的内容以及本地没有的内容从源站点获取并保留在本地。Cache 设施的数量、规模、总服务能力是掂量一个 CDN 零碎服务能力的最根本的指标。
  • 负载平衡零碎: 次要性能是负责对所有发动服务申请的用户进行拜访调度,确定提供给用户的最终理论拜访地址。两级调度体系分为全局负载平衡(GSLB)和本地负载平衡(SLB)。全局负载平衡 次要依据用户就近性准则,通过对每个服务节点进行“最优”判断,确定向用户提供服务的 cache 的物理地位。本地负载平衡 次要负责节点外部的设施负载平衡
  • 经营管理系统: 经营管理系统分为经营治理和网络管理子系统,负责解决业务层面的与外界零碎交互所必须的收集、整顿、交付工作,蕴含客户治理、产品治理、计费治理、统计分析等性能。

如何提⾼ 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 不扫描该文件,这种形式对于大型的类库很有帮忙

await 到底在等啥?

await 在期待什么呢? 一般来说,都认为 await 是在期待一个 async 函数实现。不过按语法阐明,await 期待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值(换句话说,就是没有非凡限定)。

因为 async 函数返回一个 Promise 对象,所以 await 能够用于期待一个 async 函数的返回值——这也能够说是 await 在等 async 函数,但要分明,它等的理论是一个返回值。留神到 await 不仅仅用于等 Promise 对象,它能够等任意表达式的后果,所以,await 前面理论是能够接一般函数调用或者间接量的。所以上面这个示例齐全能够正确运行:

function getSomething() {return "something";}
async function testAsync() {return Promise.resolve("hello async");
}
async function test() {const v1 = await getSomething();
    const v2 = await testAsync();
    console.log(v1, v2);
}
test();

await 表达式的运算后果取决于它等的是什么。

  • 如果它等到的不是一个 Promise 对象,那 await 表达式的运算后果就是它等到的货色。
  • 如果它等到的是一个 Promise 对象,await 就忙起来了,它会阻塞前面的代码,等着 Promise 对象 resolve,而后失去 resolve 的值,作为 await 表达式的运算后果。

来看一个例子:

function testAsy(x){return new Promise(resolve=>{setTimeout(() => {resolve(x);
     }, 3000)
    }
   )
}
async function testAwt(){let result =  await testAsy('hello world');
  console.log(result);    // 3 秒钟之后呈现 hello world
  console.log('cuger')   // 3 秒钟之后呈现 cug
}
testAwt();
console.log('cug')  // 立刻输入 cug

这就是 await 必须用在 async 函数中的起因。async 函数调用不会造成阻塞,它外部所有的阻塞都被封装在一个 Promise 对象中异步执行。await 暂停以后 async 的执行,所以 ’cug” 最先输入,hello world’ 和‘cuger’是 3 秒钟后同时呈现的。

深拷贝(思考到复制 Symbol 类型)

题目形容: 手写 new 操作符实现

实现代码如下:

function isObject(val) {return typeof val === "object" && val !== null;}

function deepClone(obj, hash = new WeakMap()) {if (!isObject(obj)) return obj;
  if (hash.has(obj)) {return hash.get(obj);
  }
  let target = Array.isArray(obj) ? [] : {};
  hash.set(obj, target);
  Reflect.ownKeys(obj).forEach((item) => {if (isObject(obj[item])) {target[item] = deepClone(obj[item], hash);
    } else {target[item] = obj[item];
    }
  });

  return target;
}

// var obj1 = {
// a:1,
// b:{a:2}
// };
// var obj2 = deepClone(obj1);
// console.log(obj1);

常见的图片格式及应用场景

(1)BMP,是无损的、既反对索引色也反对间接色的点阵图。这种图片格式简直没有对数据进行压缩,所以 BMP 格局的图片通常是较大的文件。

(2)GIF是无损的、采纳索引色的点阵图。采纳 LZW 压缩算法进行编码。文件小,是 GIF 格局的长处,同时,GIF 格局还具备反对动画以及通明的长处。然而 GIF 格局仅反对 8bit 的索引色,所以 GIF 格局实用于对色调要求不高同时须要文件体积较小的场景。

(3)JPEG是有损的、采纳间接色的点阵图。JPEG 的图片的长处是采纳了间接色,得益于更丰盛的色调,JPEG 非常适合用来存储照片,与 GIF 相比,JPEG 不适宜用来存储企业 Logo、线框类的图。因为有损压缩会导致图片含糊,而间接色的选用,又会导致图片文件较 GIF 更大。

(4)PNG-8是无损的、应用索引色的点阵图。PNG 是一种比拟新的图片格式,PNG- 8 是十分好的 GIF 格局替代者,在可能的状况下,应该尽可能的应用 PNG- 8 而不是 GIF,因为在雷同的图片成果下,PNG- 8 具备更小的文件体积。除此之外,PNG- 8 还反对透明度的调节,而 GIF 并不反对。除非须要动画的反对,否则没有理由应用 GIF 而不是 PNG-8。

(5)PNG-24是无损的、应用间接色的点阵图。PNG-24 的长处在于它压缩了图片的数据,使得同样成果的图片,PNG-24 格局的文件大小要比 BMP 小得多。当然,PNG24 的图片还是要比 JPEG、GIF、PNG- 8 大得多。

(6)SVG是无损的矢量图。SVG 是矢量图意味着 SVG 图片由直线和曲线以及绘制它们的办法组成。当放大 SVG 图片时,看到的还是线和曲线,而不会呈现像素点。这意味着 SVG 图片在放大时,不会失真,所以它非常适合用来绘制 Logo、Icon 等。

(7)WebP是谷歌开发的一种新图片格式,WebP 是同时反对有损和无损压缩的、应用间接色的点阵图。从名字就可以看进去它是为 Web 而生的,什么叫为 Web 而生呢?就是说雷同品质的图片,WebP 具备更小的文件体积。当初网站上充斥了大量的图片,如果可能升高每一个图片的文件大小,那么将大大减少浏览器和服务器之间的数据传输量,进而升高拜访提早,晋升拜访体验。目前只有 Chrome 浏览器和 Opera 浏览器反对 WebP 格局,兼容性不太好。

  • 在无损压缩的状况下,雷同品质的 WebP 图片,文件大小要比 PNG 小 26%;
  • 在有损压缩的状况下,具备雷同图片精度的 WebP 图片,文件大小要比 JPEG 小 25%~34%;
  • WebP 图片格式反对图片透明度,一个无损压缩的 WebP 图片,如果要反对透明度只须要 22% 的分外文件大小。

浏览器本地存储形式及应用场景

(1)Cookie

Cookie 是最早被提出来的本地存储形式,在此之前,服务端是无奈判断网络中的两个申请是否是同一用户发动的,为解决这个问题,Cookie 就呈现了。Cookie 的大小只有 4kb,它是一种纯文本文件,每次发动 HTTP 申请都会携带 Cookie。

Cookie 的个性:

  • Cookie 一旦创立胜利,名称就无奈批改
  • Cookie 是无奈跨域名的,也就是说 a 域名和 b 域名下的 cookie 是无奈共享的,这也是由 Cookie 的隐衷安全性决定的,这样就可能阻止非法获取其余网站的 Cookie
  • 每个域名下 Cookie 的数量不能超过 20 个,每个 Cookie 的大小不能超过 4kb
  • 有平安问题,如果 Cookie 被拦挡了,那就可取得 session 的所有信息,即便加密也于事无补,无需晓得 cookie 的意义,只有转发 cookie 就能达到目标
  • Cookie 在申请一个新的页面的时候都会被发送过来

如果须要域名之间跨域共享 Cookie,有两种办法:

  1. 应用 Nginx 反向代理
  2. 在一个站点登陆之后,往其余网站写 Cookie。服务端的 Session 存储到一个节点,Cookie 存储 sessionId

Cookie 的应用场景:

  • 最常见的应用场景就是 Cookie 和 session 联合应用,咱们将 sessionId 存储到 Cookie 中,每次发申请都会携带这个 sessionId,这样服务端就晓得是谁发动的申请,从而响应相应的信息。
  • 能够用来统计页面的点击次数

(2)LocalStorage

LocalStorage 是 HTML5 新引入的个性,因为有的时候咱们存储的信息较大,Cookie 就不能满足咱们的需要,这时候 LocalStorage 就派上用场了。

LocalStorage 的长处:

  • 在大小方面,LocalStorage 的大小个别为 5MB,能够贮存更多的信息
  • LocalStorage 是长久贮存,并不会随着页面的敞开而隐没,除非被动清理,不然会永恒存在
  • 仅贮存在本地,不像 Cookie 那样每次 HTTP 申请都会被携带

LocalStorage 的毛病:

  • 存在浏览器兼容问题,IE8 以下版本的浏览器不反对
  • 如果浏览器设置为隐衷模式,那咱们将无奈读取到 LocalStorage
  • LocalStorage 受到同源策略的限度,即端口、协定、主机地址有任何一个不雷同,都不会拜访

LocalStorage 的罕用 API:

// 保留数据到 localStorage
localStorage.setItem('key', 'value');

// 从 localStorage 获取数据
let data = localStorage.getItem('key');

// 从 localStorage 删除保留的数据
localStorage.removeItem('key');

// 从 localStorage 删除所有保留的数据
localStorage.clear();

// 获取某个索引的 Key
localStorage.key(index)

LocalStorage 的应用场景:

  • 有些网站有换肤的性能,这时候就能够将换肤的信息存储在本地的 LocalStorage 中,当须要换肤的时候,间接操作 LocalStorage 即可
  • 在网站中的用户浏览信息也会存储在 LocalStorage 中,还有网站的一些不常变动的个人信息等也能够存储在本地的 LocalStorage 中

(3)SessionStorage

SessionStorage 和 LocalStorage 都是在 HTML5 才提出来的存储计划,SessionStorage 次要用于长期保留同一窗口 (或标签页) 的数据,刷新页面时不会删除,敞开窗口或标签页之后将会删除这些数据。

SessionStorage 与 LocalStorage 比照:

  • SessionStorage 和 LocalStorage 都在 本地进行数据存储
  • SessionStorage 也有同源策略的限度,然而 SessionStorage 有一条更加严格的限度,SessionStorage只有在同一浏览器的同一窗口下才可能共享
  • LocalStorage 和 SessionStorage都不能被爬虫爬取

SessionStorage 的罕用 API:

// 保留数据到 sessionStorage
sessionStorage.setItem('key', 'value');

// 从 sessionStorage 获取数据
let data = sessionStorage.getItem('key');

// 从 sessionStorage 删除保留的数据
sessionStorage.removeItem('key');

// 从 sessionStorage 删除所有保留的数据
sessionStorage.clear();

// 获取某个索引的 Key
sessionStorage.key(index)

SessionStorage 的应用场景

  • 因为 SessionStorage 具备时效性,所以能够用来存储一些网站的游客登录的信息,还有长期的浏览记录的信息。当敞开网站之后,这些信息也就随之打消了。

说一下 SPA 单页面有什么优缺点?

长处:1. 体验好,不刷新,缩小 申请  数据 ajax 异步获取 页面流程;2. 前后端拆散

3. 加重服务端压力

4. 共用一套后端程序代码,适配多端

毛病:1. 首屏加载过慢;2.SEO 不利于搜索引擎抓取

为什么函数的 arguments 参数是类数组而不是数组?如何遍历类数组?

arguments是一个对象,它的属性是从 0 开始顺次递增的数字,还有 calleelength等属性,与数组类似;然而它却没有数组常见的办法属性,如 forEach, reduce 等,所以叫它们类数组。

要遍历类数组,有三个办法:

(1)将数组的办法利用到类数组上,这时候就能够应用 callapply办法,如:

function foo(){Array.prototype.forEach.call(arguments, a => console.log(a))
}

(2)应用 Array.from 办法将类数组转化成数组:‌

function foo(){const arrArgs = Array.from(arguments) 
  arrArgs.forEach(a => console.log(a))
}

(3)应用开展运算符将类数组转化成数组

function foo(){const arrArgs = [...arguments] 
    arrArgs.forEach(a => console.log(a)) 
}

setTimeout、setInterval、requestAnimationFrame 各有什么特点?

异步编程当然少不了定时器了,常见的定时器函数有 setTimeoutsetIntervalrequestAnimationFrame。最罕用的是setTimeout,很多人认为 setTimeout 是延时多久,那就应该是多久后执行。

其实这个观点是谬误的,因为 JS 是单线程执行的,如果后面的代码影响了性能,就会导致 setTimeout 不会按期执行。当然了,能够通过代码去修改 setTimeout,从而使定时器绝对精确:

let period = 60 * 1000 * 60 * 2
let startTime = new Date().getTime()
let count = 0
let end = new Date().getTime() + period
let interval = 1000
let currentInterval = interval
function loop() {
  count++
  // 代码执行所耗费的工夫
  let offset = new Date().getTime() - (startTime + count * interval);
  let diff = end - new Date().getTime()
  let h = Math.floor(diff / (60 * 1000 * 60))
  let hdiff = diff % (60 * 1000 * 60)
  let m = Math.floor(hdiff / (60 * 1000))
  let mdiff = hdiff % (60 * 1000)
  let s = mdiff / (1000)
  let sCeil = Math.ceil(s)
  let sFloor = Math.floor(s)
  // 失去下一次循环所耗费的工夫
  currentInterval = interval - offset 
  console.log('时:'+h, '分:'+m, '毫秒:'+s, '秒向上取整:'+sCeil, '代码执行工夫:'+offset, '下次循环距离'+currentInterval) 
  setTimeout(loop, currentInterval)
}
setTimeout(loop, currentInterval)

接下来看 setInterval,其实这个函数作用和 setTimeout 基本一致,只是该函数是每隔一段时间执行一次回调函数。

通常来说不倡议应用 setInterval。第一,它和 setTimeout 一样,不能保障在预期的工夫执行工作。第二,它存在执行累积的问题,请看以下伪代码

function demo() {setInterval(function(){console.log(2)
  },1000)
  sleep(2000)
}
demo()

以上代码在浏览器环境中,如果定时器执行过程中呈现了耗时操作,多个回调函数会在耗时操作完结当前同时执行,这样可能就会带来性能上的问题。

如果有循环定时器的需要,其实齐全能够通过 requestAnimationFrame 来实现:

function setInterval(callback, interval) {
  let timer
  const now = Date.now
  let startTime = now()
  let endTime = startTime
  const loop = () => {timer = window.requestAnimationFrame(loop)
    endTime = now()
    if (endTime - startTime >= interval) {startTime = endTime = now()
      callback(timer)
    }
  }
  timer = window.requestAnimationFrame(loop)
  return timer
}
let a = 0
setInterval(timer => {console.log(1)
  a++
  if (a === 3) cancelAnimationFrame(timer)
}, 1000)

首先 requestAnimationFrame 自带函数节流性能,根本能够保障在 16.6 毫秒内只执行一次(不掉帧的状况下),并且该函数的延时成果是准确的,没有其余定时器工夫不准的问题,当然你也能够通过该函数来实现 setTimeout

== 操作符的强制类型转换规定?

对于 == 来说,如果比照单方的类型 不一样 ,就会进行 类型转换。如果比照 xy 是否雷同,就会进行如下判断流程:

  1. 首先会判断两者类型是否 雷同,雷同的话就比拟两者的大小;
  2. 类型不雷同的话,就会进行类型转换;
  3. 会先判断是否在比照 nullundefined,是的话就会返回 true
  4. 判断两者类型是否为 stringnumber,是的话就会将字符串转换为 number
1 == '1'
      ↓
1 ==  1
  1. 判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断
'1' == true
        ↓
'1' ==  1
        ↓
 1  ==  1
  1. 判断其中一方是否为 object 且另一方为 stringnumber 或者 symbol,是的话就会把 object 转为原始类型再进行判断
'1' == {name: 'js'}        ↓'1' == '[object Object]'

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

  • 伪元素:在内容元素的前后插入额定的元素或款式,然而这些元素实际上并不在文档中生成。它们只在内部显示可见,但不会在文档的源代码中找到它们,因而,称为“伪”元素。例如:
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}

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

代码输入后果

var a, b
(function () {console.log(a);
   console.log(b);
   var a = (b = 3);
   console.log(a);
   console.log(b);   
})()
console.log(a);
console.log(b);

输入后果:

undefined 
undefined 
3 
3 
undefined 
3

这个题目和下面题目考查的知识点相似,b 赋值为 3,b 此时是一个全局变量,而将 3 赋值给 a,a 是一个局部变量,所以最初打印的时候,a 仍旧是 undefined。

什么是同源策略

跨域问题其实就是浏览器的同源策略造成的。

同源策略限度了从同一个源加载的文档或脚本如何与另一个源的资源进行交互。这是浏览器的一个用于隔离潜在歹意文件的重要的平安机制。同源指的是:协定 端口号 域名 必须统一。

同源策略:protocol(协定)、domain(域名)、port(端口)三者必须统一。

同源政策次要限度了三个方面:

  • 以后域下的 js 脚本不可能拜访其余域下的 cookie、localStorage 和 indexDB。
  • 以后域下的 js 脚本不可能操作拜访操作其余域下的 DOM。
  • 以后域下 ajax 无奈发送跨域申请。

同源政策的目标次要是为了保障用户的信息安全,它只是对 js 脚本的一种限度,并不是对浏览器的限度,对于个别的 img、或者 script 脚本申请都不会有跨域的限度,这是因为这些操作都不会通过响应后果来进行可能呈现平安问题的操作。

TCP 和 UDP 的概念及特点

TCP 和 UDP 都是传输层协定,他们都属于 TCP/IP 协定族:

(1)UDP

UDP 的全称是 用户数据报协定,在网络中它与 TCP 协定一样用于解决数据包,是一种无连贯的协定。在 OSI 模型中,在传输层,处于 IP 协定的上一层。UDP 有不提供数据包分组、组装和不能对数据包进行排序的毛病,也就是说,当报文发送之后,是无奈得悉其是否平安残缺达到的。

它的特点如下:

1)面向无连贯

首先 UDP 是不须要和 TCP 一样在发送数据前进行三次握手建设连贯的,想发数据就能够开始发送了。并且也只是数据报文的搬运工,不会对数据报文进行任何拆分和拼接操作。

具体来说就是:

  • 在发送端,应用层将数据传递给传输层的 UDP 协定,UDP 只会给数据减少一个 UDP 头标识下是 UDP 协定,而后就传递给网络层了
  • 在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,不会任何拼接操作

2)有单播,多播,播送的性能

UDP 不止反对一对一的传输方式,同样反对一对多,多对多,多对一的形式,也就是说 UDP 提供了单播,多播,播送的性能。

3)面向报文

发送方的 UDP 对应用程序交下来的报文,在增加首部后就向下交付 IP 层。UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。因而,应用程序必须抉择适合大小的报文

4)不可靠性

首先不可靠性体现在无连贯上,通信都不须要建设连贯,想发就发,这样的状况必定不牢靠。

并且收到什么数据就传递什么数据,并且也不会备份数据,发送数据也不会关怀对方是否曾经正确接管到数据了。

再者网络环境时好时坏,然而 UDP 因为没有拥塞管制,始终会以恒定的速度发送数据。即便网络条件不好,也不会对发送速率进行调整。这样实现的弊病就是在网络条件不好的状况下可能会导致丢包,然而长处也很显著,在某些实时性要求高的场景(比方电话会议)就须要应用 UDP 而不是 TCP。

5)头部开销小,传输数据报文时是很高效的。

UDP 头部蕴含了以下几个数据:

  • 两个十六位的端口号,别离为源端口(可选字段)和指标端口
  • 整个数据报文的长度
  • 整个数据报文的测验和(IPv4 可选字段),该字段用于发现头部信息和数据中的谬误

因而 UDP 的头部开销小,只有 8 字节,相比 TCP 的至多 20 字节要少得多,在传输数据报文时是很高效的。

(2)TCP TCP 的全称是传输控制协议是一种面向连贯的、牢靠的、基于字节流的传输层通信协议。TCP 是面向连贯的、牢靠的流协定(流就是指不间断的数据结构)。

它有以下几个特点:

1)面向连贯

面向连贯,是指发送数据之前必须在两端建设连贯。建设连贯的办法是“三次握手”,这样能建设牢靠的连贯。建设连贯,是为数据的牢靠传输打下了根底。

2)仅反对单播传输

每条 TCP 传输连贯只能有两个端点,只能进行点对点的数据传输,不反对多播和播送传输方式。

3)面向字节流

TCP 不像 UDP 一样那样一个个报文独立地传输,而是在不保留报文边界的状况下以字节流形式进行传输。

4)牢靠传输

对于牢靠传输,判断丢包、误码靠的是 TCP 的段编号以及确认号。TCP 为了保障报文传输的牢靠,就给每个包一个序号,同时序号也保障了传送到接收端实体的包的按序接管。而后接收端实体对已胜利收到的字节发回一个相应的确认 (ACK);如果发送端实体在正当的往返时延(RTT) 内未收到确认,那么对应的数据(假如失落了)将会被重传。

5)提供拥塞管制

当网络呈现拥塞的时候,TCP 可能减小向网络注入数据的速率和数量,缓解拥塞。

6)提供全双工通信

TCP 容许通信单方的应用程序在任何时候都能发送数据,因为 TCP 连贯的两端都设有缓存,用来长期寄存双向通信的数据。当然,TCP 能够立刻发送一个数据段,也能够缓存一段时间以便一次发送更多的数据段(最大的数据段大小取决于 MSS)

说一下怎么把类数组转换为数组?

// 通过 call 调用数组的 slice 办法来实现转换
Array.prototype.slice.call(arrayLike)

// 通过 call 调用数组的 splice 办法来实现转换
Array.prototype.splice.call(arrayLike,0)

// 通过 apply 调用数组的 concat 办法来实现转换
Array.prototype.concat.apply([],arrayLike)

// 通过 Array.from 办法来实现转换
Array.from(arrayLike)
退出移动版