👇 內容速覽 👇javascript
this
仍是一道經典題目,下面的這段代碼的輸出是什麼?(爲了方便解釋,輸出放在了註釋中)html
function fn() { console.log(this); // 1. {a: 100} var arr = [1, 2, 3]; (function() { console.log(this); // 2. Window })(); // 普通 JS arr.map(function(item) { console.log(this); // 3. Window return item + 1; }); // 箭頭函數 let brr = arr.map(item => { console.log("es6", this); // 4. {a: 100} return item + 1; }); } fn.call({ a: 100 });
其實訣竅很簡單,常見的基本是3種狀況:es5普通函數、es6的箭頭函數以及經過bind
改變過上下文返回的新函數。前端
① es5普通函數:java
window
obj.foo()
,上下文就是對象自己obj
new
調用,this
綁定在返回的實例上② es6箭頭函數: 它自己沒有this
,會沿着做用域向上尋找,直到global
/ window
。請看下面的這段代碼:webpack
function run() { const inner = () => { return () => { console.log(this.a) } } inner()() } run.bind({a: 1})() // Output: 1
③ bind綁定上下文返回的新函數:就是被第一個bind綁定的上下文,並且bind對「箭頭函數」無效。請看下面的這段代碼:css3
function run() { console.log(this.a) } run.bind({a: 1})() // output: 1 // 屢次bind,上下文由第一個bind的上下文決定 run .bind({a: 2}) .bind({a: 1}) () // output: 2
最後,再說說這幾種方法的優先級:new > bind > 對象調用 > 直接調用git
至此,這道題目的輸出就說能夠解釋明白了。es6
題目:JS中的原始數據類型?
ECMAScript 中定義了 7 種原始類型:github
注意:原始類型不包含Object和Function
題目:經常使用的判斷方法?
在進行判斷的時候有typeof
、instanceof
。對於數組的判斷,使用Array.isArray()
:
typeof:
typeof null
和typeof [1, 2, 3]
均返回"object"typeof Symbol()
返回"symbol"instanceof:
專門用於實例和構造函數對應
function Obj(value){ this.value = value; } let obj = new Obj("test"); console.log(obj instanceof Obj); // output: true
[1, 2, 3] instanceof Array
Array.isArray({})
返回false
。當咱們對一個「對象」進行數學運算操做時候,會涉及到對象 => 基礎數據類型的轉化問題。
事實上,當一個對象執行例如加法操做的時候,若是它是原始類型,那麼就不須要轉換。不然,將遵循如下規則:
valueOf()
方法,若是有返回的是基礎類型,中止下面的過程;不然繼續toString()
方法,若是有返回的是基礎類型,中止下面的過程;不然繼續請看下面的測試代碼:
let a = { toString: function() { return 'a' } } let b = { valueOf: function() { return 100 }, toString: function() { return 'b' } } let c = Object.create(null) // 建立一個空對象 console.log(a + '123') // output: a123 console.log(b + 1) // output: 101 console.log(c + '123') // 報錯
除了valueOf
和toString
,es6還提供了Symbol.toPrimitive
供對象向原始類型轉化,而且它的優先級最高!!稍微改造下上面的代碼:
let b = { valueOf: function() { return 100 }, toString: function() { return 'b' }, [Symbol.toPrimitive]: function() { return 10000 } } console.log(b + 1) // output: 10001
最後,其實關於instanceof
判斷是不是某個對象的實例,es6也提供了Symbol.hasInstance
接口,代碼以下:
class Even { static [Symbol.hasInstance](num) { return Number(num) % 2 === 0; } } const Odd = { [Symbol.hasInstance](num) { return Number(num) % 2 !== 0; } }; console.log(1 instanceof Even); // output: false console.log(1 instanceof Odd); // output: true
題目:實現對象的深拷貝。
在JS中,函數和對象都是淺拷貝(地址引用);其餘的,例如布爾值、數字等基礎數據類型都是深拷貝(值引用)。
值得提醒的是,ES6的Object.assign()
和ES7的...
解構運算符都是「淺拷貝」。實現深拷貝仍是須要本身手動擼「輪子」或者藉助第三方庫(例如lodash
):
extend(true, result, src1, src2[ ,src3])
、lodash的cloneDeep(src)
JSON.parse(JSON.stringify(src))
:這種方法有侷限性,若是屬性值是函數或者一個類的實例的時候,沒法正確拷貝藉助HTML5的MessageChannel
:這種方法有侷限性,當屬性值是函數的時候,會報錯
<script> function deepClone(obj) { return new Promise(resolve => { const {port1, port2} = new MessageChannel(); port2.onmessage = ev => resolve(ev.data); port1.postMessage(obj); }); } const obj = { a: 1, b: { c: [1, 2], d: '() => {}' } }; deepClone(obj) .then(obj2 => { obj2.b.c[0] = 100; console.log(obj.b.c); // output: [1, 2] console.log(obj2.b.c); // output: [100, 2] }) </script>
事件流分爲:冒泡和捕獲,順序是先捕獲再冒泡。
事件冒泡:子元素的觸發事件會一直向父節點傳遞,一直到根結點中止。此過程當中,能夠在每一個節點捕捉到相關事件。能夠經過stopPropagation
方法終止冒泡。
事件捕獲:和「事件冒泡」相反,從根節點開始執行,一直向子節點傳遞,直到目標節點。
addEventListener
給出了第三個參數同時支持冒泡與捕獲:默認是false
,事件冒泡;設置爲true
時,是事件捕獲。
<div id="app" style="width: 100vw; background: red;"> <span id="btn">點我</span> </div> <script> // 事件捕獲:先輸出 "外層click事件觸發"; 再輸出 "內層click事件觸發" var useCapture = true; var btn = document.getElementById("btn"); btn.addEventListener( "click", function() { console.log("內層click事件觸發"); }, useCapture ); var app = document.getElementById("app"); app.onclick = function() { console.log("外層click事件觸發"); }; </script>
DOM2級:前面說的addEventListener
,它定義了DOM
事件流,捕獲 + 冒泡。
DOM0級:
on
事件on
系列事件注意:如今通用DOM2
級事件,優勢以下:
沒什麼好說的,跑一下下面的代碼就能夠理解了:
// map: 生成一個新數組,遍歷原數組, // 將每一個元素拿出來作一些變換而後放入到新的數組中 let newArr = [1, 2, 3].map(item => item * 2); console.log(`New array is ${newArr}`); // filter: 數組過濾, 根據返回的boolean // 決定是否添加到數組中 let newArr2 = [1, 2, 4, 6].filter(item => item !== 6); console.log(`New array2 is ${newArr2}`); // reduce: 結果彙總爲單個返回值 // acc: 累計值; current: 當前item let arr = [1, 2, 3]; const sum = arr.reduce((acc, current) => acc + current); const sum2 = arr.reduce((acc, current) => acc + current, 100); console.log(sum); // 6 console.log(sum2); // 106
《前端知識體系》
《設計模式手冊》
《Webpack4漸進式教程》