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 。