event loop
Promise
内部的语句是当即执行的,以上所说的微任务 Promise
指的是 Promise.then
function p(){ return new Promise(resolve => { console.log('resolve') resolve() }) } p().then(() => { console.log('hello') }) console.log('hi') // 'resolve' 'hi' 'hello'
let a = 0 let b = async () => { a = a + await 10 console.log('2', a) } b() a++ console.log('1', a) // -> '1' 1 // -> '2' 10
setTimeinterval
和 setTimeout
准确吗,缘由?因为 javascript 的 event loop
机制,setTimeinterval
和 setTimeout
须要在主线程任务和微任务结束后执行,这就意味着若是主线程的处理时间超出了设置的时间时这两种方法确定是不许确的javascript
setTimeout
,setInterval
在 event loop
的宏任务中,当主线程结束时才会按照任务队列加载css
requestAnimationFrame
在主线程中执行,因此更加准确,以1秒钟60次(大约每16.7毫秒一次)的频率执行html
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)
函数 & 防抖前端
在 javascript 中,一切皆对象,而每一个对象都会有一个 __proto__
属性, __proto__
指向实例化该对象的构造函数的 prototype
,而该构造函数的 __proto__
又指向它的构造函数的 __proto__
如此往复向下,直到底层为 null
时中止,当调用一个对象的方法时,javascript 会顺着这条线寻找该方法。vue
prototype
,class
java
特色node
使用 ==
时,若是两边值的类型不一样会触发类型转换,因此会出现 Boolean('1' == 1) === true
,使用 ===
时则不会webpack
函数 A 内部有一个函数 B,函数 B 能够访问到函数 A 中的变量,那么函数 B 就是闭包git
for (var i = 1; i <= 5; i++) { setTimeout(function timer() { console.log(i) }, i * 1000) } // 6个6
深拷贝 & 浅拷贝github
Function.prototype.myCall = function(context) { if (typeof this !== 'function') { throw new TypeError('Error') } context = context || window context.fn = this const args = [...arguments].slice(1) const result = context.fn(...args) delete context.fn return result } Function.prototype.myApply = function(context) { if (typeof this !== 'function') { throw new TypeError('Error') } context = context || window context.fn = this let result if (arguments[1]) { result = context.fn(...arguments[1]) } else { result = context.fn() } delete context.fn return result } Function.prototype.myBind = function (context) { if (typeof this !== 'function') { throw new TypeError('Error') } const _this = this const args = [...arguments].slice(1) // 返回一个函数 return function F() { if (this instanceof F) { return new _this(...args, ...arguments) } return _this.apply(context, args.concat(...arguments)) } }
function create() { let obj = {} let Con = [].shift.call(arguments) obj.__proto__ = Con.prototype let result = Con.apply(obj, arguments) return result instanceof Object ? result : obj }
instanceof
能够正确的判断对象的类型,由于内部机制是经过判断对象的原型链中是否是能找到类型的 prototype
。
function myInstanceof(left, right) { let prototype = right.prototype left = left.__proto__ while (true) { if (left === null || left === undefined) return false if (prototype === left) return true left = left.__proto__ } }
冒泡:由小及大,从子元素事件发出,向父元素,父元素的父元素...直至 html
为止
捕获:由大及小,从父元素发出,向其下的子元素...直至最小的元素为止
使用 element.addEventListener(type,listener,options)
,在 options.capture
设置使用冒泡仍是捕获,默认冒泡
通常使用在有大量或者是动态渲染的html元素须要绑定事件时,以达到提升性能或动态绑定的目的。
将事件绑定在 html 元素的父元素上,经过事件流的冒泡属性,在父元素中获取到点击的子元素,加以判断后实行相应的事件。
当协议、域名或者端口有一个不一样便是跨域,浏览器会拦截 ajax 请求,目的是为了防止 CSRF 攻击。简单点说,CSRF 攻击是利用用户的登陆态发起恶意请求。
浏览器拦截的是读取内容的请求,因此经过表单等方式的请求是不会被拦截的
仅在同域名和同域名不一样文件夹下两种状况时不存在跨域,其他皆为跨域
<script>
标签没有跨域限制的漏洞。经过 <script>
标签指向一个须要访问的地址并提供一个回调函数来接收数据当须要通信时。function jsonp(url, jsonpCallback, success) { let script = document.createElement('script') script.src = url script.async = true script.type = 'text/javascript' window[jsonpCallback] = function(data) { success && success(data) } document.body.appendChild(script) } jsonp('http://xxx', 'callback', function(value) { console.log(value) })
该方式只能用于二级域名相同的状况下,好比 a.test.com 和 b.test.com 适用于该方式。
只须要给页面添加 document.domain = 'test.com' 表示二级域名都相同就能够实现跨域
主要用于页面和其下的 iframe 之间的通信
async
属性为 defer
重绘仅改变节点的外观,不影响布局,如改变节点的 color 属性
回流指节点的大小或页面的布局发生改变
回流一定会发生重绘,重绘不必定会引起回流
header包含:
请求的方法(get、post、put..) 协议(http、https、ftp、sftp…) 目标url(具体的请求路径已经文件名) 一些必要信息(缓存、cookie之类)
body包含:
请求的内容
script
标签时会等待其中 js
代码执行完成后继续执行上述步骤(会形成阻塞)// ES5 function Animal() { this.type = 'animal' this.eat = function(){} } function Cat() { Animal.call(this) this.name = 'cat' } function inherits(Child, Parent) { var F = function () {}; F.prototype = Parent.prototype; Child.prototype = new F(); Child.prototype.constructor = Child; } // ES6 class Fruit{ constructor(){} } class Apple extends Fruit{ constructor(){ super() } }
先明确:虚拟 dom (框架封装的)不必定比 原生 dom 快 参考
好处:
简化dom操做,让数据与dom之间的关系更直观更简单
用于加载某些资源文件。 由于webpack 自己只能打包commonjs规范的js文件,对于其余资源例如 css,图片,或者其余的语法集,好比 jsx, coffee,是没有办法加载的。 这就须要对应的loader将资源转化,加载进来。从字面意思也能看出,loader是用于加载的,它做用于一个个文件上。
用于扩展webpack的功能。它直接做用于 webpack,扩展了它的功能。固然loader也时变相的扩展了 webpack ,可是它只专一于转化文件(transform)这一个领域。而plugin的功能更加的丰富,而不只局限于资源的加载。
一般浏览器缓存策略分为两种:强缓存和协商缓存,而且缓存策略都是经过设置 HTTP Header 来实现的。
强缓存能够经过设置两种 HTTP Header 实现:Expires 和 Cache-Control 。强缓存表示在缓存期间不须要请求,state code 为 200。
若是缓存过时了,就须要发起请求验证资源是否有更新。协商缓存能够经过设置两种 HTTP Header 实现:Last-Modified 和 ETag 。