2019前端面試題2

 

1,如何理解CSS的盒子模型?

標準盒子模型:寬度=內容的寬度(content)+ border + padding

低版本IE盒子模型:寬度=內容寬度(content+border+padding)

2,BFC?

* 什麼是 BFC

   BFC(Block Formatting Context)格式化上下文,是 Web 頁面中盒模型佈局的 CSS 渲染模式,指一個獨立的渲染區域或者說是一個隔離的獨立容器。
* 造成 BFC 的條件

   * 浮動元素,float 除 none 之外的值 * 定位元素,position(absolute,fixed) * display 爲如下其中之一的值 inline-block,table-cell,table-caption * overflow 除了 visible 之外的值(hidden,auto,scroll) * BFC 的特性 * 內部的 Box 會在垂直方向上一個接一個的放置。 * 垂直方向上的距離由 margin 決定 * bfc 的區域不會與 float 的元素區域重疊。 * 計算 bfc 的高度時,浮動元素也參與計算 * bfc 就是頁面上的一個獨立容器,容器裏面的子元素不會影響外面元素。 

3,如何清除浮動?

不清楚浮動會發生高度塌陷:浮動元素父元素高度自適應(父元素不寫高度時,子元素寫了浮動後,父元素會發生高度塌陷)
* clear清除浮動(添加空div法)在浮動元素下方添加空div,並給該元素寫css樣式: {clear:both;height:0;overflow:hidden;} * 給浮動元素父級設置高度 * 父級同時浮動(須要給父級同級元素添加浮動) * 父級設置成inline-block,其margin: 0 auto居中方式失效 * 給父級添加overflow:hidden 清除浮動方法 * 萬能清除法 after僞類 清浮動(如今主流方法,推薦使用) .float_div:after{ content:"."; clear:both; display:block; height:0; overflow:hidden; visibility:hidden; } .float_div{ zoom:1 } 

4,用純CSS建立一個三角形的原理是什麼?

span { width: 0; height: 0; border-top: 40px solid transparent; border-left: 40px solid transparent; border-right: 40px solid transparent; border-bottom: 40px solid #ff0000; } 
 
圖片

5,CSS3實現0.5px的細線?

/* css */ .line { position: relative; } .line:after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 1px; background-color: #000000; -webkit-transform: scaleY(.5); transform: scaleY(.5); } /* html */ <div class="line"></div> 

6,CSS實現三欄佈局

左右固定,中間自適應。javascript

 
圖片
  1. 柔性方式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box { display: flex; justify-content: center; height: 200px; } .left { width: 200px; background-color: red; height: 100%; } .content { background-color: yellow; flex: 1; } .right { width: 200px; background-color: green; } </style> </head> <body> <div class="box"> <div class="left"></div> <div class="content"></div> <div class="right"></div> </div> </body> </html> 
  1. 絕對定位方式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box { position: relative; height: 200px; } .left { width: 200px; background-color: red; left: 0; height: 100%; position: absolute; } .content { background-color: yellow; left: 200px; right: 200px; height: 100%; position: absolute; } .right { width: 200px; background-color: green; right: 0; height: 100%; position: absolute; } </style> </head> <body> <div class="box"> <div class="left"></div> <div class="content"></div> <div class="right"></div> </div> </body> </html> 
  1. 浮動方式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box { height: 200px; } .left { width: 200px; background-color: red; float: left; height: 100%; } .content { background-color: yellow; height: 100%; } .right { width: 200px; background-color: green; float: right; height: 100%; } </style> </head> <body> <div class="box"> <div class="left"></div> <div class="right"></div> <div class="content"></div> </div> </body> </html> 

7,讓一個DIV垂直居中

 
圖片
  1. 寬度和高度已知的
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box { width: 400px; height: 200px; position: relative; background: red; } .content { width: 200px; height: 100px; position: absolute; top: 50%; left: 50%; margin-left: -100px; margin-top: -50px; background: green; } </style> </head> <body> <div class="box"> <div class="content"></div> </div> </body> </html> 
  1. 寬度和高度未知
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box { width: 400px; height: 200px; position: relative; background: red; } .content { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: green; } </style> </head> <body> <div class="box"> <div class="content"></div> </div> </body> </html> 
  1. 柔性佈局
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box { width: 400px; height: 200px; background: red; display: flex; justify-content: center; align-items: center; } .content { width: 200px; height: 100px; background: green; } </style> </head> <body> <div class="box"> <div class="content"></div> </div> </body> </html> 

二,JS

1,閉包

閉包概念php

可以讀取其餘函數內部變量的函數。
或簡單理解爲定義在一個函數內部的函數,內部函數持有外部函數內變量的引用。

閉包用途css

一、讀取函數內部的變量
二、讓這些變量的值始終保持在內存中。不會再f1調用後被自動清除。
三、方便調用上下文的局部變量。利於代碼封裝。
緣由:f1是f2的父函數,f2被賦給了一個全局變量,f2始終存在內存中,f2的存在依賴f1,所以f1也始終存在內存中,不會在調用結束後,被垃圾回收機制回收。

閉包缺點html

一、因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大,因此不能濫用閉包,不然會形成網頁的性能問題,在IE中可能致使內存泄露。解決方法是,在退出函數以前,將不使用的局部變量所有刪除。 二、閉包會在父函數外部,改變父函數內部變量的值。因此,若是你把父函數看成對象(object)使用,把閉包看成它的公用方法(Public Method),把內部變量看成它的私有屬性(private value),這時必定要當心,不要隨便改變父函數內部變量的值。 

閉包應用場景vue

閉包應用場景之的setTimeoutjava

//setTimeout傳遞的第一個函數不能帶參數 setTimeout((param) => { alert(param) }, 1000); //經過閉包能夠實現傳參效果 function func(param) { return function() { alert(param) } } var f1 = func('汪某'); setTimeout(f1, 1000)//汪某 

2,JS中函數執行

在ES5.1裏面函數是這樣執行的(不討論使用嚴格和一些特殊狀況,JS好複雜的),按以下順序執行:nginx

1. 肯定「this」的值 (確切的來講,this在JS裏面不是一個變量名而是一個關鍵字) 2. 建立一個新的做用域 3. 處理形參/實參(沒有定義過才聲明,不管如何都從新賦值,沒有對應實參則賦值爲"undefined"): 對於每個傳入的實參,按照從左往右的順序依次執行:若是對應的形參在本做用域中尚未定義,則在本做用域中聲明形參,並賦值。若是已經定義過了,則從新給其賦值。(沒有對應實參則賦值爲"undefined")(沒有定義:就是「沒有聲明」的意思) 4. 處理函數定義(沒有定義過才聲明,不管如何都從新賦值): 對該函數中全部的定義的函數,按照代碼寫的順序依次執行:若是這個變量名在本做用域中尚未定義,則在本做用域中聲明這個函數名,而且賦值爲對應的函數,若是定義了這個變量,在可寫的狀況下從新給這個變量賦值爲這個函數,不然拋出異常。 5. 處理 "arguments"(沒有定義過才聲明和賦值): 若是在本做用域中沒有定義 arguments,則在本做用域中聲明arguments並給其賦值。 6. 處理變量聲明(沒有定義過才聲明,不賦值): 對於全部變量聲明,按照代碼寫的順序依次執行:若是在本做用域中沒有定義這個變量,則在本做用域中聲明這個變量,賦值爲undefined 7. 而後執行函數代碼。(固然是去變量定義裏面的 var 執行) 

3,新的一個對象的過程當中發生了什麼嘛

1. 建立空對象; var obj = {}; 2. 設置新對象的constructor屬性爲構造函數的名稱,設置新對象的__proto__屬性指向構造函數的prototype對象; obj.__proto__ = ClassA.prototype; 3. 使用新對象調用函數,函數中的this被指向新實例對象: ClassA.call(obj);//{}.構造函數(); 4. 若是無返回值或者返回一個非對象值,則將新對象返回;若是返回值是一個新對象的話那麼直接直接返回該對象。 

4,宏任務跟微任務

  • 宏觀任務(宏任務):包括總體代碼腳本的setTimeout,setInterval的
  • 微任務(微任務):無極,process.nextTick

這一次,完全弄懂JavaScript執行機制web

5,防抖和節流

綜合應用場景面試

  • 防抖(debounce):就是指觸發事件後在n秒內函數只能執行一次,若是在n秒內又觸發了事件,則會從新計算函數執行時間。
    • 搜索搜索聯想,用戶在不斷輸入值時,用防抖來節約請求資源。
    • 窗口觸發調整的時候,不斷的調整瀏覽器窗口大小會不斷的觸發這個事件,用防抖來讓其只觸發一次
  • 節流(油門):就是指連續觸發事件可是在n秒中只執行一次函數。節流會稀釋函數的執行頻率。
    • 鼠標不斷點擊觸發,鼠標按下(單位時間內只觸發一次)
    • 監聽滾動事件,好比是否滑到底部自動加載更多,用油門來判斷
      所謂防抖,就是指觸發事件後在n秒內函數只能執行一次,若是在n秒內又觸發了事件,則會從新計算函數執行時間。

防抖函數分爲非當即執行版和當即執行版。算法

  • 非當即執行版的意思是觸發事件後函數不會當即執行,而是在n秒後執行,若是在n秒內又觸發了事件,則會從新計算函數執行時間。
  • 當即執行版的意思是觸發事件後函數會當即執行,而後n秒內不觸發事件才能繼續執行函數的效果。
/** * @desc 函數防抖 * @param func 函數 * @param wait 延遲執行毫秒數 * @param immediate true 表當即執行,false 表非當即執行 */ function debounce(func,wait,immediate) { let timeout; return function () { let context = this; let args = arguments; if (timeout) clearTimeout(timeout); if (immediate) { var callNow = !timeout; timeout = setTimeout(() => { timeout = null; }, wait) if (callNow) func.apply(context, args) } else { timeout = setTimeout(function(){ func.apply(context, args) }, wait); } } } 

所謂節流,就是指連續觸發事件可是在n秒中只執行一次函數。節流會稀釋函數的執行頻率。

對於節流,通常有兩種方式能夠實現,分別是時間戳版和定時器版。

  • 時間戳版的函數觸發是在時間段內開始的時候
  • 定時器版的函數觸發是在時間段內結束的時候。
/** * @desc 函數節流 * @param func 函數 * @param wait 延遲執行毫秒數 * @param type 1 表時間戳版,2 表定時器版 */ function throttle(func, wait ,type) { if(type===1){ var previous = 0; }else if(type===2){ var timeout; } return function() { let context = this; let args = arguments; if(type===1){ let now = Date.now(); if (now - previous > wait) { func.apply(context, args); previous = now; } }else if(type===2){ if (!timeout) { timeout = setTimeout(() => { timeout = null; func.apply(context, args) }, wait) } } } } 

6,數組的經常使用方法

改變原數組的方法

  • splice()添加/刪除數組元素
語法:arrayObject.splice(index,howmany,item1,.....,itemX)
參數:
   1.index:必需。整數,規定添加/刪除項目的位置,使用負數可從數組結尾處規定位置。
   2.howmany:可選。要刪除的項目數量。若是設置爲 0,則不會刪除項目。
   3.item1, ..., itemX: 可選。向數組添加的新項目。

返回值: 若是有元素被刪除,返回包含被刪除項目的新數組。
  • sort()數組排序
語法:arrayObject.sort(sortby) 參數: 1.sortby 可選。規定排序順序。必須是函數。。 返回值: 返回包排序後的新數組。 
  • pop()刪除一個數組中的最後的一個元素
語法:arrayObject.pop() 參數:無 返回值: 返回被刪除的元素。 
  • shift()刪除數組的第一個元素
語法:arrayObject.shift() 參數:無 返回值: 返回被刪除的元素。 
  • push()向數組的末尾添加元素
語法:arrayObject.push(newelement1,newelement2,....,newelementX) 參數: 1.newelement1 必需。要添加到數組的第一個元素。 2.newelement2 可選。要添加到數組的第二個元素。 3.newelementX 可選。可添加若干個元素。 返回值: arrayObject 的新長度。 
  • unshift()向數組的開頭添加一個或更多元素
語法:arrayObject.unshift(newelement1,newelement2,....,newelementX) 參數: 1.newelement1 必需。要添加到數組的第一個元素。 2.newelement2 可選。要添加到數組的第二個元素。 3.newelementX 可選。可添加若干個元素。 返回值: arrayObject 的新長度。 
  • reverse()顛倒數組中元素的順序
語法:arrayObject.reverse() 參數:無 返回值: 顛倒後的新數組。 
  • copyWithin()指定位置的成員複製到其餘位置
語法: array.copyWithin(target, start = 0, end = this.length) 參數: 1.target(必需):從該位置開始替換數據。若是爲負值,表示倒數。 2.start(可選):從該位置開始讀取數據,默認爲 0。若是爲負值,表示倒數。 3.end(可選):到該位置前中止讀取數據,默認等於數組長度。若是爲負值,表示倒數。 返回值: 返回當前數組。 
  • fill()填充數組
語法: array.fill(value, start, end) 參數: 1.value 必需。填充的值。 2.start 可選。開始填充位置。 3.end 可選。中止填充位置 (默認爲 array.length) 返回值: 返回當前數組。 

不改變原數組的方法

  • slice()淺拷貝數組的元素
語法: array.slice(begin, end); 參數: 1.begin(可選): 索引數值,接受負值,從該索引處開始提取原數組中的元素,默認值爲0。 2.end(可選):索引數值(不包括),接受負值,在該索引處前結束提取原數組元素,默認值爲數組末尾(包括最後一個元素)。 返回值: 返回一個從開始到結束(不包括結束)選擇的數組的一部分淺拷貝到一個新數組對象,且原數組不會被修改。 
  • join()數組轉字符串
語法:array.join(str) 參數: 1.str(可選): 指定要使用的分隔符,默認使用逗號做爲分隔符。 返回值: 返回生成的字符串。 
  • concat()合併兩個或多個數組
語法: var newArr =oldArray.concat(arrayX,arrayX,......,arrayX) 參數: 1.arrayX(必須):該參數能夠是具體的值,也能夠是數組對象。能夠是任意多個。 返回值: 返回返回合併後的新數組。 
  • indexOf()查找數組是否存在某個元素
語法:array.indexOf(searchElement,fromIndex) 參數: 1.searchElement(必須):被查找的元素 2.fromIndex(可選):開始查找的位置(不能大於等於數組的長度,返回-1),接受負值,默認值爲0。 返回值: 返回下標 
  • lastIndexOf()查找指定元素在數組中的最後一個位置
語法:arr.lastIndexOf(searchElement,fromIndex) 參數: 1.searchElement(必須): 被查找的元素 2.fromIndex(可選): 逆向查找開始位置,默認值數組的長度-1,即查找整個數組。 返回值: 方法返回指定元素,在數組中的最後一個的索引,若是不存在則返回 -1。(從數組後面往前查找) 
  • includes()查找數組是否包含某個元素
語法: array.includes(searchElement,fromIndex=0) 參數: 1.searchElement(必須):被查找的元素 2.fromIndex(可選):默認值爲0,參數表示搜索的起始位置,接受負值。正值超過數組長度,數組不會被搜索,返回false。負值絕對值超過長數組度,重置從0開始搜索。 返回值: 返回布爾 

7,當即執行函數

聲明一個匿名函數,立刻調用這個匿名函數。目的是保護內部變量不受污染。

(function(n1, n2) { console.log("這是匿名函數的自執行的第一種寫法,結果爲:" + (n1 + n2)) })(10, 100); (function start(n1, n2) { console.log("這是函數聲明方式的自執行的第一種寫法,結果爲:" + (n1 + n2)) })(10, 100); (function(n1, n2) { console.log("這是匿名函數的自執行的第二種寫法,結果爲:" + (n1 + n2)) }(10, 100)); (function start(n1, n2) { console.log("這是函數聲明方式的自執行的第二種寫法,結果爲:" + (n1 + n2)) }(10, 100)); 

8,JS原型和原型鏈

每一個對象都會在其內部初始化一個屬性,就是原型(原型),當咱們訪問一個對象的屬性時,若是這個對象內部不存在這個屬性,那麼他就會去原型裏找這個屬性,這個原型又會有本身的原型,因而就這樣一直找下去,也就是咱們平時所說的原型鏈的概念。

關係:instance.constructor.prototype = instance。

特色:JavaScript的對象是經過引用來傳遞的,咱們建立的每一個新對象實體中並無一份屬於本身的原型副本,當咱們修改原型時,相關與之對象的繼承也會改變這一
當咱們須要一個屬性時,JavaScript的引擎會先看當前對象中是否有這個屬性,若是沒有的話,就會查找它的原型對象是否有這個屬性,如此遞推下去,一致檢索到的對象內建對象。

function Func(){} Func.prototype.name = "汪某"; Func.prototype.getInfo = function() { return this.name; } var person = new Func(); console.log(person.getInfo());//"汪某" console.log(Func.prototype);//Func { name = "汪某", getInfo = function() } 

參考:js原型和原型鏈

9,JS中調用,應用,綁定

參考:JavaScript中調用,應用,綁定方法的總結。

10,承諾

一句話歸納無極:無極對象用於異步操做,它表示一個還沒有完成且預計在將來完成的異步操做。

承諾是用來解決兩個問題的:

  • 回調地獄,代碼難以維護,經常第一個的函數的輸出是第二個函數的輸入這種現象
  • 承諾能夠支持多個併發的請求,獲取併發請求中的數據

這個承諾能夠解決異步的問題,自己不能說的承諾是異步的

/*Promise 的簡單實現*/ class MyPromise { constructor(fn) { this.resolvedCallbacks = []; this.rejectedCallbacks = []; this.state = "PADDING"; this.value = ""; fn(this.resolve.bind(this), this.reject.bind(this)); } resolve(value) { if (this.state === "PADDING") { this.state = "RESOLVED"; this.value = value; this.resolvedCallbacks.forEach(cb => cb()); } } reject(value) { if (this.state === "PADDING") { this.state = "REJECTED"; this.value = value; this.rejectedCallbacks.forEach(cb => cb()); } } then(resolve = function() {}, reject = function() {}) { if (this.state === "PADDING") { this.resolvedCallbacks.push(resolve); this.rejectedCallbacks.push(reject); } if (this.state === "RESOLVED") { resolve(this.value); } if (this.state === "REJECTED") { reject(this.value); } } } 

11,異步/ AWAIT

如何使用Async函數

async function timeout(ms) { await new Promise((resolve) => { setTimeout(resolve, ms); }); } async function asyncPrint(value, ms) { await timeout(ms); console.log(value); } asyncPrint('hello world', 50); 

上面代碼指定50毫秒之後,輸出hello world。進一步說,async函數徹底能夠看做多個異步操做,包裝成的一個Promise對象,而等待命令就是內部而後命令的語法糖。

待補充......

12,深拷貝,淺拷貝

淺拷貝和深拷貝都只針對於引用數據類型,淺拷貝只複製指向某個對象的指針,而不復制對象自己,新舊對象仍是共享同一塊內存;但深拷貝會另外創造一個如出一轍的對象,新對象跟原對象不共享內存,修改新對象不會改到原對象;

區別:淺拷貝只複製對象的第一層屬性,深拷貝能夠對對象的屬性進行遞歸複製;

 

 
圖片

淺拷貝的實現方式

 

  1. 自定義函數
function simpleCopy (initalObj) { var obj = {}; for ( var i in initalObj) { obj[i] = initalObj[i]; } return obj; } 
  1. ES6的Object.assign()
let newObj = Object.assign({}, obj); 
  1. ES6的對象擴展
let newObj = {...obj}; 

深拷貝的實現方式

  1. JSON.stringify和JSON.parse

用JSON.stringify把對象轉換成字符串,再用JSON.parse把字符串轉換成新的對象。

let newObj = JSON.parse(JSON.stringify(obj)); 
  1. lodash

用lodash函數庫提供的_.cloneDeep方法實現深拷貝。

var _ = require('lodash'); var newObj = _.cloneDeep(obj); 
  1. 本身封裝
function deepClone(obj) { let objClone = Array.isArray(obj) ? [] : {}; if (obj && typeof obj === "object") { // for...in 會把繼承的屬性一塊兒遍歷 for (let key in obj) { // 判斷是否是自有屬性,而不是繼承屬性 if (obj.hasOwnProperty(key)) { //判斷ojb子元素是否爲對象或數組,若是是,遞歸複製 if (obj[key] && typeof obj[key] === "object") { objClone[key] = this.deepClone(obj[key]); } else { //若是不是,簡單複製 objClone[key] = obj[key]; } } } } return objClone; } 

13,跨域

跨域須要針對瀏覽器的同源策略來理解,同源策略指的是請求必須是同一個端口,同一個協議,同一個域名,不一樣源的客戶端腳本在沒有明確受權的狀況下,不能讀寫對方資源。

受瀏覽器同源策略的影響,不是同源的腳本不能操做其餘源下面的對象。想要操做另外一個源下的對象是就須要跨域。

  • JSONP
  • IFRAME
  • 跨域資源共享(CORS)
  • nginx代理跨域

14,for in for for

  • for in
1.通常用於遍歷對象的可枚舉屬性。以及對象從構造函數原型中繼承的屬性。對於每一個不一樣的屬性,語句都會被執行。 2.不建議使用for in 遍歷數組,由於輸出的順序是不固定的。 3.若是迭代的對象的變量值是null或者undefined, for in不執行循環體,建議在使用for in循環以前,先檢查該對象的值是否是null或者undefined 
  • 由於
1.for…of 語句在可迭代對象(包括 Array,Map,Set,String,TypedArray,arguments 對象等等)上建立一個迭代循環,調用自定義迭代鉤子,併爲每一個不一樣屬性的值執行語句 

遍歷對象

var s = { a: 1, b: 2, c: 3 } var s1 = Object.create(s); for (var prop in s1) { console.log(prop); //a b c console.log(s1[prop]); //1 2 3 } for (let prop of s1) { console.log(prop); //報錯以下 Uncaught TypeError: s1 is not iterable } for (let prop of Object.keys(s1)) { console.log(prop); // a b c console.log(s1[prop]); //1 2 3 } 

15,如何阻止冒泡?

冒泡型事件:事件按照從最特定的事件目標到最不特定的事件目標(文件對象)的順序觸發。

w3c的方法是e.stopPropagation(),IE則是使用e.cancelBubble = true。

//阻止冒泡行爲 function stopBubble(e) { //若是提供了事件對象,則這是一個非IE瀏覽器 if ( e && e.stopPropagation ) //所以它支持W3C的stopPropagation()方法 e.stopPropagation(); else //不然,咱們須要使用IE的方式來取消事件冒泡 window.event.cancelBubble = true; } 

16,如何阻止默認事件?

w3c的方法是e.preventDefault(),IE則是使用e.returnValue = false

//阻止瀏覽器的默認行爲 function stopDefault( e ) { //阻止默認瀏覽器動做(W3C) if ( e && e.preventDefault ) e.preventDefault(); //IE中阻止函數器默認動做的方式 else window.event.returnValue = false; return false; } 

17,VAR,讓,常量

//變量提高 console.log(a); // undefined console.log(b); // 報錯 console.log(c); // 報錯 var a = 1; let b = 2; const c = 3; // 全局聲明 console.log(window.a) // 1 // 重複聲明 let b = 200;//報錯 

其實這裏很容易理解,var是能夠變量提高的。而讓和const是必須聲明後才能調用的。對於let和const來講,這裏就是暫緩性死區。


 
圖片

18,類

ES6新增的類其實也是語法糖,JS底層其實沒有類的概念的,其實也是原型繼承的封裝。

class People { constructor(props) { this.props = props; this.name = '汪某'; } callMyName() { console.log(this.name); } } class Name extends People { // extends 其實就是繼承了哪一個類 constructor(props) { // super至關於 把類的原型拿過來 // People.call(this, props) super(props) } callMyApple() { console.log('我是汪某!') } } let a = new Name('啊啊啊') a.callMyName(); //汪某 a.callMyApple(); // 我是汪某! 

19,設置

<font color = red>設置</ font>數據結構相似數組,但全部成員的值惟一。

let a = new Set(); [1,2,2,1,3,4,5,4,5].forEach(x=>a.add(x)); for(let k of a){ console.log(k) }; // 1 2 3 4 5 

基本使用

let a = new Set([1,2,3,3,4]); [...a]; // [1,2,3,4] a.size; // 4 // 數組去重 [...new Set([1,2,3,4,4,4])];// [1,2,3,4] 

方法

  • add(value):添加某個值,返回設置結構自己。
  • 刪除(值):刪除某個值,返回一個布爾值,表示刪除是否成功。
  • 有(值):返回一個布爾值,表示該值是否爲集的成員。
  • 清晰():清除全部成員,沒有返回值。
let a = new Set(); a.add(1).add(2); // a => Set(2) {1, 2} a.has(2); // true a.has(3); // false a.delete(2); // true a => Set(1) {1} a.clear(); // a => Set(0) {} 

20,地圖

<font color = red> Map </ font>結構提供了「值 - 值」的對應,是一種更完善的Hash結構實現。

let a = new Map(); let b = {name: 'leo' }; a.set(b,'my name'); // 添加值 a.get(b); // 獲取值 a.size; // 獲取總數 a.has(b); // 查詢是否存在 a.delete(b); // 刪除一個值 a.clear(); // 清空全部成員 無返回 

基本使用

  • 傳入數組做爲參數,指定鍵值對的數組。
let a = new Map([ ['name','wzx'], ['age',23] ]) 
  • 若是對同一個鍵屢次賦值,後面的值將覆蓋前面的值。
let a = new Map(); a.set(1,'aaa').set(1,'bbb'); a.get(1); // 'bbb' 
  • 若是讀取一個未知的鍵,則返回不肯定的。
new Map().get('asdsad'); // undefined 
  • 一樣的值的兩個實例,在地圖結構中被視爲兩個鍵。
let a = new Map(); let a1 = ['aaa']; let a2 = ['aaa']; a.set(a1,111).set(a2,222); a.get(a1); // 111 a.get(a2); // 222 

方法

  • 鍵():返回鍵名的遍歷器。
  • 值():返回鍵值的遍歷器。
  • 項():返回全部成員的遍歷器。
  • forEach():遍歷Map的全部成員。
let a = new Map([ ['name', 'leo'], ['age', 18] ]) for (let i of a.keys()) { console.log(i) }; //name //age for (let i of a.values()) { console.log(i) }; //leo //18 for (let i of a.entries()) { console.log(i) }; //["name", "leo"] a.forEach((v, k, m) => { console.log(`key:${k},value:${v},map:${m}`) }) //["age", 18] 

三,手擼代碼

1,實現一個新的操做符

function New(func) { var res = {}; if (func.prototype !== null) { res.__proto__ = func.prototype; } var ret = func.apply(res, Array.prototype.slice.call(arguments, 1)); if ((typeof ret === "object" || typeof ret === "function") && ret !== null) { return; ret; } return; res; } var obj = New(A, 1, 2); // equals to var obj = new A(1, 2); 

2,實現一個召喚或申請

  • 呼叫
Function.prototype.call2 = function (context) { var context = context || window; context.fn = this; var args = []; for(var i = 1, len = arguments.length; i < len; i++) { args.push('arguments[' + i + ']'); } var result = eval('context.fn(' + args +')'); delete context.fn return result; } 
  • 應用
Function.prototype.apply2 = function (context, arr) { var context = Object(context) || window; context.fn = this; var result; if (!arr) { result = context.fn(); } else { var args = []; for (var i = 0, len = arr.length; i < len; i++) { args.push('arr[' + i + ']'); } result = eval('context.fn(' + args + ')') } delete context.fn return result; } 

參考:JavaScript深刻之調和應用的模擬實現

3,實現一個Function.bind

Function.prototype.bind2 = function (context) { if (typeof this !== "function") { throw new Error("Function.prototype.bind - what is trying to be bound is not callable"); } var self = this; var args = Array.prototype.slice.call(arguments, 1); var fNOP = function () {}; var fbound = function () { self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments))); } fNOP.prototype = this.prototype; fbound.prototype = new fNOP(); return fbound; } 

參考:JavaScript深刻之綁的模擬實現

如圖4所示,實現一個繼承

function Parent(name) { this.name = name; } Parent.prototype.sayName = function() { console.log('parent name:', this.name); } function Child(name, parentName) { Parent.call(this, parentName); this.name = name; } function create(proto) { function F() {} F.prototype = proto; return new F(); } Child.prototype = create(Parent.prototype); Child.prototype.sayName = function() { console.log('child name:', this.name); } Child.prototype.constructor = Child; var parent = new Parent('汪某'); parent.sayName();// parent name: 汪某 var child = new Child('son', '汪某'); 

5,手寫一個無極(中高級必考)

面試夠用版

function myPromise(constructor) { let self = this; self.status = "pending" //定義狀態改變前的初始狀態 self.value = undefined; //定義狀態爲resolved的時候的狀態 self.reason = undefined; //定義狀態爲rejected的時候的狀態 function resolve(value) { //兩個==="pending",保證了狀態的改變是不可逆的 if (self.status === "pending") { self.value = value; self.status = "resolved"; } } function reject(reason) { //兩個==="pending",保證了狀態的改變是不可逆的 if (self.status === "pending") { self.reason = reason; self.status = "rejected"; } } //捕獲構造異常 try { constructor(resolve, reject); } catch (e) { reject(e); } } //同時,須要在 myPromise的原型上定義鏈式調用的 then方法: myPromise.prototype.then = function(onFullfilled, onRejected) { let self = this; switch (self.status) { case "resolved": onFullfilled(self.value); break; case "rejected": onRejected(self.reason); break; default: } } //測試一下: var p = new myPromise(function(resolve, reject) { resolve(1) }); p.then(function(x) { console.log(x) }) 

高級版請參考:史上最最最詳細的手寫承諾教程

6,手寫防抖(去抖動)和節流(節流)

完整版詳見上方,此處給出面試版

// 防抖函數 function debounce(fn, wait) { let timer; return function() { if (timer) clearTimeout(timer) timer = setTimeout(() => { fn.apply(this, arguments) }, wait) } } 
// 節流函數 function throttle(fn, wait) { let prev = new Date(); return function() { const args = arguments; const now = new Date(); if (now - prev > wait) { fn.apply(this, args); prev = new Date(); } } } 

7,手寫一個JS深拷貝

面試版

function deepCopy(obj) { //判斷是不是簡單數據類型, if (typeof obj == "object") { //複雜數據類型 var result = obj.constructor == Array ? [] : {}; for (let i in obj) { result[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i]; } } else { //簡單數據類型 直接 == 賦值 var result = obj; } return result; } 

四,VUE

1,Vue2.0的雙向數據綁定原理是什麼?

vue.js是採用數據劫持結合發佈者 - 訂閱者模式的方式,經過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調。

//vue實現數據雙向綁定的原理就是用Object.defineproperty()從新定義(set方法)對象設置屬性值和(get方法)獲取屬性值的操縱來實現的。
//Object.property()方法的解釋:Object.property(參數1,參數2,參數3)  返回值爲該對象obj
//其中參數1爲該對象(obj),參數2爲要定義或修改的對象的屬性名,參數3爲屬性描述符,屬性描述符是一個對象,主要有兩種形式:數據描述符和存取描述符。這兩種對象只能選擇一種使用,不能混合使用。而get和set屬於存取描述符對象的屬性。
//這個方法會直接在一個對象上定義一個新屬性或者修改對象上的現有屬性,並返回該對象。

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <div id="myapp"> <input v-model="message" /><br> <span v-bind="message"></span> </div> <script type="text/javascript"> var model = { message: "" }; var models = myapp.querySelectorAll("[v-model=message]"); for (var i = 0; i < models.length; i++) { models[i].onkeyup = function() { model[this.getAttribute("v-model")] = this.value; } } // 觀察者模式 / 鉤子函數 // defineProperty 來定義一個對象的某個屬性 Object.defineProperty(model, "message", { set: function(newValue) { var binds = myapp.querySelectorAll("[v-bind=message]"); for (var i = 0; i < binds.length; i++) { binds[i].innerHTML = newValue; }; var models = myapp.querySelectorAll("[v-model=message]"); for (var i = 0; i < models.length; i++) { models[i].value = newValue; }; this.value = newValue; }, get: function() { return this.value; } }) </script> </body> </html> 

Vue3.0將用原生代理替換Object.defineProperty

爲何要替換Object.defineProperty?

  • 在Vue公司中,Object.defineProperty沒法監控到數組下標的變化,致使直接經過數組的下標給數組設置值,不能實時響應。
  • Object.defineProperty只能劫持對象的屬性,所以咱們須要對每一個對象的每一個屬性進行遍歷。

什麼是代理

  • 代理是ES6中新增的一個特性,翻譯過來意思是「代理」,用在這裏表示由它來「代理」某些操做。代理讓咱們可以以簡潔易懂的方式控制外部對對象的訪問。功能很是相似於設計模式中的代理模式。
  • 代理能夠理解成,在目標對象以前架設一層「攔截」,外部對該對象的訪問,都必須先經過這層攔截,所以提供了一種機制,能夠對外界的訪問進行過濾和改寫。
  • 使用代理的核心優勢是能夠交由它來處理一些非核心邏輯(如:讀取或設置對象的某些屬性前記錄日誌;設置對象的某些屬性值前,須要驗證;某些屬性的訪問控制等)。從而可讓對象只需關注於核心邏輯,達到關注點分離,下降對象複雜度等目的。

2,請詳細說下你對VUE生命週期的理解?

總共分爲8個階段建立前/後,載入前/後,更新前/後,銷燬前/後

  • beforeCreate建立前執行(vue實例的掛載元素$ el和數據對象數據都爲undefined,還未初始化)
  • created完成建立(完成了數據初始化,el還未初始化)
  • beforeMount載入前(vue實例的$ el和data都初始化了,但仍是掛載以前爲虛擬的dom節點,data.message還未替換。)
  • mount載入後html已經渲染(vue實例掛載完成,data.message成功渲染。)
  • beforeUpdate更新前狀態(view層的數據變化前,不是data中的數據改變前)
  • 更新更新狀態後
  • beforeDestroy銷燬前
  • destroy銷燬後(在執行毀滅方法後,對數據的改變不會再觸發周期函數,說明此時vue實例已經解除了事件監聽以及和dom的綁定,可是dom結構依然存在)

說一下每個階段能夠作的事情

  • beforeCreate:能夠在這裏加一個裝載事件,在加載實例時觸發。
  • 建立:初始化完成時的事件寫這裏,若是這裏結束了裝載事件,異步請求也在這裏調用。
  • 安裝:掛在元素,獲取到DOM節點
  • 更新:對數據進行處理的函數寫這裏。
  • beforeDestroy:能夠寫一個確認中止事件的確認框。

附上一張中文解析圖


 
圖片

3,動態路由定義和獲取

在路由器目錄下的index.js文件中,對路徑屬性加上/:id。

使用路由器對象的params.id獲取

4,vue-router有哪幾種導航鉤子?

三種

  1. 全局導航鉤子(跳轉前進行判斷攔截)
    • router.beforeEach(to,from,next),
    • router.beforeResolve(to,from,next),
    • router.afterEach(to,from,next)
  2. 組件內鉤子
    • beforeRouteEnter
    • beforeRouteUpdate
    • beforeRouteLeave
  3. 單獨路由獨享組件
    • beforeEnter

5,組件之間的傳值通訊?

  • 父組件向子組件傳值:
    • 子組件在道具中建立一個屬性,用來接收父組件傳過來的值;
    • 在父組件中註冊子組件;
    • 在子組件標籤中添加子組件的道具中建立的屬性;
    • 把須要傳給子組件的值賦給該屬性
  • 子組件向父組件傳值:
    • 子組件中須要以某種方式(如點擊事件)的方法來觸發一個自定義的事件;
    • 將須要傳的值做爲$ EMIT的第二個參數,該值將做爲實參傳給響應事件的方法;
    • 在父組件中註冊子組件並在子組件標籤上綁定自定義事件的監聽。

6,vuex

是一個能方便vue實例及其組件傳輸數據的插件方便傳輸數據,做爲公共存儲數據的一個庫

state:狀態中心

突變:更改狀態,同步的

動做:異步更改狀態

getters:獲取狀態

modules:將州分紅多個模塊,便於管理

應用場景:單頁應用中,組件之間的狀態音樂播放,登陸狀態,加入購物車。

網上找的一個通俗易懂的瞭解vuex的例子

公司有個倉庫

1.State(公司的倉庫)

2.Getter(只能取出物品,包裝一下,不能改變物品任何屬性)

3.Muitation(倉庫管理員,只有他能夠直接存儲到倉庫)

4.Action(公司的物料採購員,負責從外面買東西和接貨,要往倉庫存東西,告訴倉庫管理員要存什麼)

很是要注意的地方:只要刷新或者退出瀏覽器,倉庫清空。

7,Vue hash路由和歷史路由的區別

哈希模式URL裏面永遠帶着#號,咱們在開發當中默認使用這個模式。那麼何時要用歷史的模式呢?若是用戶考慮網址的規範那麼就須要使用歷史模式,由於歷史模式沒有#號,是個正常的URL適合推廣宣傳。固然其功能也有區別,好比咱們在開發應用程序的時候有分享頁面,那麼這個分享出去的頁面就是用VUE或是反應作的,我們把這個頁面分享到第三方的應用程序裏,有的應用程序裏面的網址是不容許帶有#號的,因此要將#號去除那麼就要使用歷史模式,可是使用的歷史模式還有一個問題就是,在訪問二級頁面的時候,作刷新操做,會出現404錯誤,那麼就須要和後端人配合讓他配置一下apache的或是nginx的的URL重定向,重定向到你的首頁路由上就OK啦。

router有兩種模式:hash模式(默認),history模式(需配置模式:'history')
 | 哈希| 歷史
- | - | -
url顯示| 有#,很低| 無#,好看|
回車刷新| 能夠加載到hash值對應頁面| 通常就是404掉了|
支持版本| 支持低版本瀏覽器和IE瀏覽器| 支持低版本瀏覽器和IE瀏覽器|

8,DIFF算法

參考:詳解VUE的差別算法

五,計算機

1,DNS解析的詳細過程

當咱們在瀏覽器中輸入一個URL,例如「 www.google.com 」時,這個地址並非谷歌網站真正意義上的地址。互聯網上每一臺計算機的惟一標識是它的IP地址,所以咱們輸入的網址首先須要先解析爲IP地址,這一過程叫作DNS解析。

DNS解析是一個遞歸查詢的過程。例如,咱們須要解析「 www.google.com 」時,會經歷如下步驟:

  • 在本地域名服務器中查詢IP地址,未找到域名;
  • 本地域名服務器迴向根域名服務器發送請求,未找到域名;
  • 本地域名服務器向.COM頂級域名服務器發送請求,未找到域名;
  • 本地域名服務器向.google.com域名服務器發送請求,找到該域名,將對應的IP返回給本地域名服務器。

2,簡述三次握手

HTTP協議是使用TCP協議做爲其傳輸層協議的,在拿到服務器的IP地址後,瀏覽器客戶端會與服務器創建TCP鏈接該過程包括三次握手:

  • 第一次握手:創建鏈接時,客戶端向服務端發送請求報文
  • 第二次握手:服務器收到請求報文後,如贊成鏈接,則向客戶端發送確認報文
  • 第三次握手,客戶端收到服務器的確認後,再次向服務器給出確認報文,完成鏈接。

三次握手主要是爲了防止已經失效的請求報文字段發送給服務器,浪費資源。

3,四次揮手

客戶端與服務器四次揮手,斷開TCP鏈接。

  • 第一次揮手:客戶端想分手,發送消息給服務器
  • 第二次揮手:服務器通知客戶端已經接受到分手請求,但還沒作好分手準備
  • 第三次回收:服務器已經作好分手準備,通知客戶端
  • 第四次揮手:客戶端發送消息給服務器,肯定分手,服務器關閉鏈接
相關文章
相關標籤/搜索