前端複習要點

可參考:juejin.im/post/5ac43e… 可參考:github.com/ltadpoles/w…javascript

1、HTML&CSS

1.文本溢出顯示省略號

  • 單行文本
<p style="width: 300px;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;">
複製代碼

width:加寬度屬性來兼容部分瀏覽器php

white-space:設置如何處理元素中的空白。詳細見:developer.mozilla.org/zh-CN/docs/…css

text-overflow:ellipsis:單行文本的溢出顯示省略號html

  • 多行文本
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
複製代碼

因使用了WebKit的CSS擴展屬性,該方法適用於WebKit瀏覽器及移動端;前端

注:-webkit-line-clamp用來限制在一個塊元素顯示的文本的行數。 爲了實現該效果,它須要組合其餘的WebKit屬性。java

常見結合屬性:ios

  • display: -webkit-box:必須結合的屬性,將對象做爲彈性伸縮盒子模型顯示 。
  • -webkit-box-orient:必須結合的屬性,設置或檢索伸縮盒對象的子元素的排列方式 。

PS:字符串中包含'\r\n' 需添加white-space: pre-line;渲染才能換行展現nginx

2.按鈕漸變+陰影

background-image: linear-gradient(-90deg, #ff62c5 0%, #ff5687 100%);
box-shadow: 0 1px 4px 0 rgba(255, 100, 145, 0.7);
複製代碼

linear-gradient(45deg, blue, red);/* 漸變軸爲45度,從藍色漸變到紅色 */git

linear-gradient(to left top, blue, red);/* 從右下到左上、從藍色漸變到紅色 */github

linear-gradient(0deg, blue, green 40%, red);/* 從下到上,從藍色開始漸變、到高度40%位置是綠色漸變開始、最後以紅色結束 */

box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);/* x偏移量 | y偏移量 | 陰影模糊半徑 | 陰影擴散半徑 | 陰影顏色 */

3.transition過渡和animation動畫

transition過渡

  • (1)transition

當鼠標放置於圖片上,圖片會迅速變大。圖片變大是瞬間實現的。

img{
    height:15px;
    width:15px;
}

img:hover{
    height: 450px;
    width: 450px;
}
複製代碼

transition的做用在於,指定狀態變化所須要的時間。

img{
    transition: 1s;
}
複製代碼

還能夠指定transition適用的屬性,好比只適用於height。只有height的變化須要1秒實現,其餘變化(主要是width)依然瞬間實現。

img{
    transition: 1s height;
}
複製代碼

height和width的變是同時進行,跟不指定它們沒有差異

img{
    transition: 1s height, 1s width;
}
複製代碼
  • (2)transition-delay 延遲變化

讓height先發生變化,等結束之後,再讓width發生變化。

img{
    transition: 1s height, 1s 1s width;
}
複製代碼
  • (3)transition-timing-function transition的狀態變化速度(又稱timing function),默認不是勻速的,而是逐漸放慢,叫作ease。
img{
    transition: 1s ease;
}
複製代碼

除了ease之外,其餘模式還包括

(1)linear:勻速

(2)ease-in:加速

(3)ease-out:減速

(4)cubic-bezier函數:自定義速度模式,cubic-bezier能夠使用工具網站來定製。

img{
    transition: 1s height cubic-bezier(.83,.97,.05,1.44);
}
複製代碼

transition的各項屬性 transition的完整寫法以下。

img{
    transition: 1s 1s height ease;
}
複製代碼

這實際上是一個簡寫形式,能夠單獨定義成各個屬性。

img{
    transition-property: height;
    transition-duration: 1s;
    transition-delay: 1s;
    transition-timing-function: ease;
}
複製代碼

animation動畫

CSS Animation須要指定動畫一個週期持續的時間,以及動畫效果的名稱。

  • (1)animation

當鼠標懸停在div元素上時,會產生名爲rainbow的動畫效果,持續時間爲1秒。爲此,咱們還須要用keyframes關鍵字,定義rainbow效果。rainbow效果一共有三個狀態,分別爲起始(0%)、中點(50%)和結束(100%)。

div:hover {
  animation: 1s rainbow;
}
@keyframes rainbow {
  0% { background: #c00; }
  50% { background: orange; }
  100% { background: yellowgreen; }
}
複製代碼

默認狀況下,動畫只播放一次。加入infinite關鍵字,可讓動畫無限次播放。

div:hover {
  animation: 1s rainbow infinite;
}
複製代碼

也能夠指定動畫具體播放的次數,好比3次。

div:hover {
  animation: 1s rainbow 3;
}
複製代碼
  • (2)animation-fill-mode:動畫結束之後,會當即從結束狀態跳回到起始狀態。若是想讓動畫保持在結束狀態,須要使用animation-fill-mode屬性。
div:hover {
  animation: 1s rainbow forwards; /* forwards表示讓動畫停留在結束狀態 */
}
複製代碼

animation-fill-mode還能夠使用下列值。

(1)none:默認值,回到動畫沒開始時的狀態。

(2)backwards:讓動畫回到第一幀的狀態。

(3)both: 根據animation-direction輪流應用forwards和backwards規則。

  • (3)animation-direction:動畫循環播放時,每次都是從結束狀態跳回到起始狀態,再開始播放。animation-direction屬性,能夠改變這種行爲。
/* 有這樣一個動畫 */
@keyframes rainbow {
  0% { background-color: yellow; }
  100% { background: blue; }
}
/* 默認狀況animation-direction等於normal */
div:hover {
  animation: 1s rainbow 3 normal;
}
複製代碼

此外,還能夠等於取alternate、reverse、alternate-reverse等值。它們的含義見下圖(假定動畫連續播放三次)。

animation的各項屬性,同transition同樣,animation也是一個簡寫形式。

div:hover {
    animation: 1s 1s rainbow linear 3 forwards normal;
}
複製代碼

這是一個簡寫形式,能夠分解成各個單獨的屬性。

div:hover {
    animation-name: rainbow;
    animation-duration: 1s;
    animation-timing-function: linear;
    animation-delay: 1s;
    animation-fill-mode:forwards;
    animation-direction: normal;
    animation-iteration-count: 3;
}
複製代碼
  • keyframes的寫法:keyframes關鍵字用來定義動畫的各個狀態,它的寫法至關自由。
@keyframes rainbow {
  0% { background: #c00 }
  50% { background: orange }
  100% { background: yellowgreen }
}
/* 0%能夠用from表明,100%能夠用to表明,所以上面的代碼等同於下面的形式。 */
@keyframes rainbow {
  from { background: #c00 }
  50% { background: orange }
  to { background: yellowgreen }
}
複製代碼

若是省略某個狀態,瀏覽器會自動推算中間狀態,因此下面都是合法的寫法。

@keyframes rainbow {
  50% { background: orange }
  to { background: yellowgreen }
}
@keyframes rainbow {
  to { background: yellowgreen }
}
/* 甚至,能夠把多個狀態寫在一行。*/
@keyframes pound {
  fromto { transform: none; }
  50% { transform: scale(1.2); }
}
/* 另一點須要注意的是,瀏覽器從一個狀態向另外一個狀態過渡,是平滑過渡。steps函數能夠實現分步過渡。*/
div:hover {
  animation: 1s rainbow infinite steps(10);
}
複製代碼
  • (4)animation-play-state:有時,動畫播放過程當中,會忽然中止。這時,默認行爲是跳回到動畫的開始狀態。

鼠標沒有懸停時,動畫狀態是暫停;一旦懸停,動畫狀態改成繼續播放。

div {
    animation: spin 1s linear infinite;
    animation-play-state: paused;
}

div:hover {
    animation-play-state: running;
}
複製代碼

注意:瀏覽器前綴,目前,IE 10和Firefox(>= 16)支持沒有前綴的animation,而chrome不支持,因此必須使用webkit前綴。

4.css僞類和僞元素(單冒號:和雙冒號::的使用)

在CSS2以前規範不明確的時候,僞元素和僞類都使用單冒號(:)來表示。

好比 :before :after :hover

而CSS3規範中的要求使用雙冒號(::)表示僞元素,以此來區分僞元素和僞類。

上面的例子用CSS3的規範就應該寫成 ::before ::after :hover

爲了兼容過去的寫法,CSS3以前的僞元素仍然能夠使用單冒號(:)來表示,瀏覽器是能夠解析的。

好比 :before 和 ::before 均可以被瀏覽器解析。

可是CSS3以後出現的僞元素必須用雙冒號表示,再也不支持單冒號的形式。

僞元素包括:

僞類包括:

5.瀏覽器的迴流與重繪 (Reflow & Repaint)

(1) Reflow

也稱做Layout,中文叫回流,通常意味着元素的內容、結構、位置或尺寸發生了變化,須要從新計算樣式和渲染樹,這個過程稱爲Reflow。

(2) Repaint

中文重繪,意味着元素髮生的改變只是影響了元素的一些外觀之類的時候(例如,背景色,邊框顏色,文字顏色等),此時只須要應用新樣式繪製這個元素就OK了,這個過程稱爲Repaint。

Reflow的成本比Repaint的成本高得多的多。DOM樹裏的每一個結點都會有reflow方法,一個結點的reflow頗有可能致使子結點,甚至父點以及同級結點的reflow。

(3) 下面這些動做有很大可能會是成本比較高的:

  • 一、增長、刪除、修改DOM結點時,會致使Reflow或Repaint。
  • 二、移動DOM的位置,或是搞個動畫的時候。
  • 三、內容發生變化。
  • 四、修改CSS樣式的時候。
  • 五、Resize窗口的時候(移動端沒有這個問題),或是滾動的時候。
  • 六、修改網頁的默認字體時。

(4) 基本上來講,reflow有以下的幾個緣由:

一、Initial,網頁初始化的時候。 二、Incremental,一些js在操做DOM樹時。 三、Resize,其些元件的尺寸變了。 四、StyleChange,若是CSS的屬性發生變化了。

6.css盒子模型,box-sizing屬性的理解

css的盒模型由content(內容)、padding(內邊距)、border(邊框)、margin(外邊距)組成。但盒子的大小由content+padding+border這幾部分決定

box-sizing是一個CSS3屬性,與盒子模型有着密切聯繫。即決定元素的寬高如何計算,box-sizing有三個屬性:

box-sizing: content-box|border-box|inherit:

標準盒模型(content-box):盒模型的寬高只是內容(content)的寬高

怪異盒模型(border-box):盒模型的寬高是內容(content)+填充(padding)+邊框(border)的總寬高

inherit 指定box-sizing屬性的值,應該從父元素繼承

7.清除浮動,何時須要清除浮動,清除浮動都有哪些方法

浮動的元素是脫離文檔標準流的,若是咱們不清楚浮動,那麼就會形成父元素高度塌陷,影響頁面佈局。

清除浮動的方式:

  • 爲父元素設置高度

  • 爲父元素添加overflow:hidden

    overflow:hidden能夠觸發BFC機制。BFC:塊級格式化上下文,建立了 BFC的元素就是一個獨立的盒子,它規定了內部如何佈局,而且與這個獨立盒子裏的佈局不受外部影響,固然它也不會影響到外面的元素,計算BFC的高度時,浮動元素也參與計算

  • 僞元素

    .fix::after { 
         content:""; 
         display:block; 
         clear:both;
    }
    複製代碼

    使用僞元素的好處:不增長冗餘的DOM節點,符合語義化

8.多標籤之間的通訊

juejin.im/post/5acdba…

9.HTML5離線存儲原理

segmentfault.com/a/119000000…

10. CSS中link 和@import的區別

link屬於XHTML標籤,@import徹底是CSS提供的一種方式,只能加載CSS

加載順序的差異,當一個頁面被加載的時候,link引用的CSS會同時被加載,而@import引用的CSS 會等到頁面所有被下載完再被加載

兼容性的差異。因爲@import是CSS2.1提出的因此老的瀏覽器不支持,而link標籤無此問題

當使用javascript控制dom去改變樣式的時候,只能使用link標籤,由於@import不是dom能夠控制的

11. offsetWidth/offsetHeight,clientWidth/clientHeight與scrollWidth/scrollHeight的區別

offsetWidth/offsetHeight返回值包含content + padding + border,效果與e.getBoundingClientRect()相同

clientWidth/clientHeight返回值只包含content + padding,若是有滾動條,也不包含滾動條

scrollWidth/scrollHeight返回值包含content + padding + 溢出內容的尺寸


2、javascript

1.JavaScript 有哪些數據類型

6種原始數據類型:

  • Boolean: 布爾表示一個邏輯實體,能夠有兩個值:true 和 false
  • Number: 用於表示數字類型
  • String: 用於表示文本數據
  • Null: Null 類型只有一個值: null,特指對象的值未設置
  • Undefined: 一個沒有被賦值的變量會有個默認值 undefined
  • Symbol: 符號(Symbols)是ECMAScript第6版新定義的。符號類型是惟一的而且是不可修改的

引用類型:Object

詳見:developer.mozilla.org/zh-CN/docs/…

2.判斷JS數據類型

  • typeof操做符:返回一個字符串,表示未經計算的操做數的類型。除了null均可以顯示正確的類型。

    typeof 操做符對於簡單數據類型,返回其自己的數據類型,函數對象返回 function ,其餘對象均返回 Object

    typeof 1 //'number'
    typeof '1' //'string'
    typeof undefined //'undefined'
    typeof true //'boolean'
    typeof Symbol() //'symbol'
    typeof b //b沒有生命,可是還會顯示undefined
    typeof [] //'object'
    typeof {} //'object'
    typeof console.log //'function'
    typeof null //'object'
    複製代碼

    null 返回 Object,出現這種狀況的緣由是:在js最第一版本中,使用的是32位系統,爲了性能考慮使用低位存儲了變量的類型信息,000開頭表明的是對象,然而null表示爲全0,因此將它錯誤的判斷成了object。雖然如今的內部類型判斷代碼已經改變了,可是這個bug仍是存在的。

  • instanceof: 用來判斷A 是不是 B的實例,表達式爲 A instanceof B,返回一個Boolean類型的值 instanceof 檢測的是原型,只能用來判斷兩個對象是否屬於實例關係, 而不能判斷一個對象實例具體屬於哪一種類型

    let a = [];
    a instanceof Array  // true
    a instanceof Object // true
    複製代碼

    變量a 的 __ proto__ 直接指向Array.prototype,間接指向 Object.prototype,因此按照 instanceof 的判斷規則,a 就是Object的實例.針對數組的這個問題,ES5 提供了 Array.isArray() 方法 。該方法用以確認某個對象自己是否爲 Array 類型

    constructor: 當一個函數被定義時,JS引擎會爲其添加prototype原型,而後再在 prototype上添加一個 constructor 屬性,並讓其指向該函數的引用

    null和undefined是無效的對象,所以是不會有constructor存在的,這兩種類型的數據須要經過其餘方式來判斷

    函數的constructor是不穩定的,這個主要體如今自定義對象上,當開發者重寫prototype後,原有的constructor引用會丟失,constructor會默認爲 Object

    function F() {};
    var f = new F;
    f.constructor == F // true
    
    F.prototype = {a: 1}
    var f = new F
    f.constructor == F // false 
    複製代碼

    在構造函數 F.prototype 沒有被重寫以前,構造函數 F 就是新建立的對象 f 的數據類型。當 F.prototype 被重寫以後,原有的 constructor 引用丟失, 默認爲 Object

    所以,爲了規範開發,在重寫對象原型時通常都須要從新給 constructor 賦值,以保證對象實例的類型不被篡改

  • toString: Object 的原型方法,調用該方法,默認返回當前對象的 [[Class]] 。這是一個內部屬性,其格式爲 [object Xxx] ,其中 Xxx 就是對象的類型。能夠得到變量的正確類型。

    Object.prototype.toString.call('') ;   // [object String]
        Object.prototype.toString.call(11) ;    // [object Number]
        Object.prototype.toString.call(true) ; // [object Boolean]
        Object.prototype.toString.call(Symbol()); //[object Symbol]
        Object.prototype.toString.call(undefined) ; // [object Undefined]
        Object.prototype.toString.call(null) ; // [object Null]
        Object.prototype.toString.call(new Function()) ; // [object Function]
        Object.prototype.toString.call([]) ; // [object Array]
    複製代碼

3.isPrototypeOf、instanceof、hasOwnProperty函數介紹

可參考: www.jianshu.com/p/44ba37660…

4.js中的強制類型轉換

參考:juejin.im/post/5b3b76…

5.js建立對象的方式

1. 對象字面量

var obj = {}
複製代碼

2. Object 構造函數

var obj = new Object()
複製代碼

3. 工廠模式

function Person(name, age) {
    var o = new Object()
    o.name = name;
    o.age = age;
    o.say = function() {
        console.log(name)
    }
    return o
}
複製代碼

缺點: 每次經過Person建立對象的時候,全部的say方法都是同樣的,可是卻存儲了屢次,浪費資源

4. 構造函數模式

function Person(name, age) {
    this.name = name
    this.age = age
    this.say = function() {
        console.log(name)
    }
}
var person = new Person('hello', 18)
複製代碼

構造函數模式,隱式地在最後return this 因此在缺乏new的狀況下,會將屬性和方法添加給全局對象,瀏覽器端就會添加給window對象,能夠根據return this 的特性調用call或者apply指定this

5. 原型模式

function Person() {}
Person.prototype.name = 'hanmeimei';
Person.prototype.say = function() {
  alert(this.name);
}
Person.prototype.friends = ['lilei'];
var person = new Person();
複製代碼

實現了方法與屬性的共享,能夠動態添加對象的屬性和方法。可是沒有辦法建立實例本身的屬性和方法,也沒有辦法傳遞參數

6. 構造函數和原型組合

function Person(name, age) {
    this.name = name
    this.age = age
}
Person.prototype.say = function() {
    console.log(this.name)
}
var person = new Person('hello')
複製代碼

6.null和undefined的區別

參考:www.ruanyifeng.com/blog/2014/0…

7.數組對象有哪些經常使用方法

修改器方法:詳細可參考:juejin.im/post/5c3ede… & juejin.im/post/5c3f01…

  • pop(): 刪除數組的最後一個元素,並返回這個元素
  • push():在數組的末尾增長一個或多個元素,並返回數組的新長度
  • reverse(): 顛倒數組中元素的排列順序
  • shift(): 刪除數組的第一個元素,並返回這個元素
  • unshift(): 在數組的開頭增長一個或多個元素,並返回數組的新長度
  • sort(): 對數組元素進行排序,並返回當前數組
  • splice(): 在任意的位置給數組添加或刪除任意個元素

訪問方法:

  • concat(): 返回一個由當前數組和其它若干個數組或者若干個非數組值組合而成的新數組
  • join(): 鏈接全部數組元素組成一個字符串
  • slice(): 抽取當前數組中的一段元素組合成一個新數組
  • indeOf(): 返回數組中第一個與指定值相等的元素的索引,若是找不到這樣的元素,則返回 -1
  • lastIndexOf(): 返回數組中最後一個(從右邊數第一個)與指定值相等的元素的索引,若是找不到這樣的元素,則返回 -1

迭代方法:詳細可參考另外一篇總結:juejin.im/post/5c2c94…

  • forEach(): 爲數組中的每一個元素執行一次回調函數,最終返回 undefined
  • every(): 若是數組中的每一個元素都知足測試函數,則返回 true,不然返回 false
  • some(): 若是數組中至少有一個元素知足測試函數,則返回 true,不然返回 false
  • filter(): 將全部在過濾函數中返回 true 的數組元素放進一個新數組中並返回
  • map(): 返回一個由回調函數的返回值組成的新數組

8.js事件模型 事件委託

1.js事件的三個階段分別爲:捕獲、目標、冒泡

  • 1.捕獲:事件由頁面元素接收,逐級向下,到具體的元素
  • 2.目標:具體的元素自己
  • 3.冒泡:跟捕獲相反,具體元素自己,逐級向上,到頁面元素

事件捕獲:當使用事件捕獲時,父級元素先觸發,子元素後觸發

事件冒泡:當使用事件冒泡時,子級元素先觸發,父元素後觸發

W3C:任何事件發生時,先從頂層開始進行事件捕獲,直到事件觸發到達事件源,再從事件源向上進行事件捕獲

標準瀏覽器:addEventListener("click","doSomething","true")方法,若第三參數爲true則採用事件捕獲,若爲false,則採用事件冒泡

IE瀏覽器只支持事件冒泡,不支持事件捕獲,因此它不支持addEventListener("click","doSomething","true")方法,因此ie瀏覽器使用ele.attachEvent("onclick",doSomething)

【事件傳播的阻止方法】

在W3C中,使用event.stopPropagation()方法

在IE下使用event.cancelBubble = true方法

【阻止默認行爲】

在W3c中,使用event.preventDefault()方法

在IE下 使用event.returnValue = false; 或 return false;

2.事件委託/代理:通俗來講就是將元素的事件委託給它的父級或者更外級元素處理

原理:利用事件冒泡機制實現的

優勢:

  • 只須要將同類元素的事件委託給父級或者更外級的元素,不須要給全部元素都綁定事件,減小內存空間佔用,提高性能 無需爲子節點註銷事件。
  • 動態新增的元素無需從新綁定事件

9.js中聲明提高、做用域(鏈)、this關鍵字和箭頭函數

參考另外一篇總結:juejin.im/post/5ca324…

10.閉包

簡單來講,閉包就是可以讀取其餘函數內部變量的函數

function Person() {
    var name = 'hello'
    function say () {
        console.log(name)
    }
    return say()
}
Person() // hello
複製代碼

因爲 JavaScript 特殊的做用域,函數外部沒法直接讀取內部的變量,內部能夠直接讀取外部的變量,從而就產生了閉包的概念

用途:

  • 以讀取函數內部的變量
  • 讓這些變量的值始終保持在內存中

注意點:

  • 因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大,因此不能濫用閉包,不然會形成網頁的性能問題,在IE中可能致使內存泄露
  • 解決方法是,在退出函數以前,將不使用的局部變量所有刪除

循環定時器例題:juejin.im/post/58f1fa…

11.call, apply, bind 區別? 怎麼實現 call,apply 方法

類似之處:

  • 都是用來改變函數的 this 對象的指向的。

  • 第一個參數都是 this 要指向的對象。

  • 均可以利用後續參數傳參。

區別:

  • call 接受函數傳參方式爲:fn.call(this, 1, 2, 3)

  • apply 接受函數傳參方式爲:fn.apply(this,[1, 2, 3])

  • bind 將函數綁定至某個對象,當在f()上調用bind()方法並傳入一個對象o做爲參數,這個方法會返回一個新的函數。以函數調用的方式調用新的函數將會把原始的函數f()當作新對象o的方法來調用。傳入新函數的任何實參都將傳入原始函數f()。

let a =  {
    value: 1
}
function getValue(name, age) {
    console.log(name);
    console.log(age);
    console.log(this.value);
}
getValue().call(a, 'zyx','24');
getValue().apply(a, ['zyx','24']);
複製代碼

不傳入第一個參數,那麼默認爲window

改變了this指向,讓新的對象能夠執行該函數。那麼能夠認爲是爲改新的對象添加一個函數,執行完之後再刪除

1. 手動實現 call 方法:

Function.prototype.myCall = function(context = window, ...rest) {//context就是傳入的第一個參數a
    context.fn = this; // this就是當前調用call的函數——即getValue;給a添加一個函數:a.fn = getValue
    let result = context.fn(...rest); //getValue(...rest)
    //將this指向銷燬
    delete context.fn;
    return result;
};
複製代碼

2. 手動實現apply

Function.prototype.myCall = function(context = window, params = []) {
    context.fn = this; //此處this是指調用myCall的function
    let result
    if (params.length) {
        result = context.fn(...params)
    }else {
        result = context.fn()
    }
    //將this指向銷燬
    delete context.fn;
    return result;
};
複製代碼

3. 手動實現 bind 方法:

var f = function(y, z) {
    return this.x + y + z;
}
var a = {x:1}
var g = f.bind(a, 2);
g(3); // => 6 this.x綁定到1,y綁定到2,z綁定到3
複製代碼
Function.prototype.myBind = function(context) {//context是a,
    if(typeof this !== 'function') { // this就是f
        throw new TypeError('Error');
    }
    var _this = this;
    var args = [...arguments].slice(1); //arguments對象是全部(非箭頭)函數中均可用的局部變量。此時arguments是 (a,2), [a,2].slice(1) => 獲得對象後面的參數args=[2]
    return function F() { //由於返回了一個函數,咱們能夠new F() 因此要判斷
        if (this instanceof F) { F就是g,若是f是g的實例 g也存在a
            return new _this(...args, ...arguments); //args=[2];arguments是F即g的參數[3];=>new f(2,3)
        }
        return _this.apply(context, args.concat(...arguments));//若是f不是g的實例,f.apply(a,[2].concat(3))=>f.apply(a,[2,3])
    }
}
複製代碼

12.原型 原型鏈 它們分別有什麼特色

原型

每一個構造函數(constructor)都有一個原型對象(prototype),原型對象都包含一個指向構造函數的指針,而實例(instance)都包含一個指向原型對象的內部指針

  • 每個構造函數都擁有一個prototype屬性,這個屬性指向一個對象,也就是原型對象
  • 原型對象默認擁有一個constructor屬性,指向指向它的那個構造函數
  • 每一個對象都擁有一個隱藏的屬性[[prototype]],指向它的原型對象

原型鏈

JavaScript中全部的對象都是由它的原型對象繼承而來。而原型對象自身也是一個對象,它也有本身的原型對象,這樣層層上溯,就造成了一個相似鏈表的結構,這就是原型鏈。

全部原型鏈的終點都是Object函數的prototype屬性。Objec.prototype指向的原型對象一樣擁有原型,不過它的原型是null,而null則沒有原型

13.JavaScript 如何實現繼承

每一個函數都有prototype屬性,除了Function.prototype.bind(),該屬性指向原型。

每一個對象都有__proto__屬性,實例的__proto__指向構造函數的 prototype。

js 引擎會沿着__proto__-> ptototype 的順序一直往上方查找,找到 Object.prototype 時,Object.prototype.__proto__又會指向 Object.ptototype,爲了不循環引用,原型鏈沒有終點,js 把 Object.prototype.__proto__設置爲 null,這樣原型鏈就有了終點。其實原型鏈查找到 Object.ptototype 這裏就中止了查找,若是沒有找到,就會報錯或者返回 undefined。

1.原型鏈繼承

最簡單的繼承實現方式,可是也有其缺點

  • 來自原型對象的全部屬性被全部實例共享
  • 建立子類實例時,沒法向父類構造函數傳參
  • 要想爲子類新增屬性和方法,必需要在new語句以後執行,不能放到構造器中
function Animal() {}
Animal.prototype.name = 'cat'
Animal.prototype.age = 1
Animal.prototype.say = function() {console.log('hello')}

var cat = new Animal()

cat.name  // cat
cat.age  // 1
cat.say() // hello
複製代碼

2. 構造繼承

使用call或apply方法,將父對象的構造函數綁定在子對象上.

function Animal() {
    this.species = "動物"
}
function Cat(name, age) {
    Animal.call(this)
    this.name = name 
    this.age = age
}

var cat = new Cat('豆豆', 2)

cat.name  // 豆豆
cat.age // 2
cat.species // 動物
複製代碼

ES5實現繼承:組合繼承,寄生組合繼承

3.組合繼承: 利用 call 繼承父類上的屬性,用子類的原型等於父類實例去繼承父類的方法

缺點:調用兩次父類,形成性能浪費

function Parent(name) {
    this.name = name;
}

Parent.prototype.say = function() {
    console.log(this.name);
};
function Child(name) {
    Parent.call(this, name)
}
Child.prototype = new Parent;//若是沒有這一行,Child.prototype.constructor是指向Child的;加了這一行之後,Child.prototype.constructor指向Parent。這顯然會致使繼承鏈的紊亂(c明明是用構造函數Child生成的),所以咱們必須手動糾正,將Child.prototype對象的constructor值改成Child
Child.prototype.constructor = Child
let c = new Child("YaoChangTuiQueDuan");
c.say()
複製代碼

4.寄生組合集成

利用call繼承父類上的屬性,用一個乾淨的函數的原型=父類原型,再用子類的原型=這個乾淨函數的原型

function Parent(name) {
    this.name = name;
}

Parent.prototype.say = function() {
    console.log(this.name);
};

function ExtendMiddle() {}

function Child(name) {
    Parent.call(this, name)
}

ExtendMiddle.prototype = Parent.prototype;
Child.prototype = new ExtendMiddle

let c = new Child("YaoChangTuiQueDuan");
c.say()

複製代碼

5.ES6 Class 能夠經過extends關鍵字實現繼承

用 extends 實現繼承,必須添加 super 關鍵字定義子類的 constructor,這裏的super() 就至關於 Animal.prototype.constructor.call(this)

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); // 調用父類的constructor(x, y)
    this.color = color;
  }

  toString() {
    return this.color + ' ' + super.toString(); // 調用父類的toString()
  }
}
複製代碼

上面代碼中,constructor方法和toString方法之中,都出現了super關鍵字,它在這裏表示父類的構造函數,用來新建父類的this對象。

爲何必定要使用super()?

子類必須在constructor方法中調用super方法,不然新建實例時會報錯。這是由於子類本身的this對象,必須先經過父類的構造函數完成塑造,獲得與父類一樣的實例屬性和方法,而後再對其進行加工,加上子類本身的實例屬性和方法。若是不調用super方法,子類就得不到this對象。

14.new 操做符具體幹了什麼

1.建立一個空對象

2.this變量引用該變量

3.繼承函數的原型,屬性和方法被加入到this引用的對象中

4.新建立的對象由this引用,而且最後隱式的返回this

對於實例對象來講,都是經過new產生的,不管是function Foo()仍是let a = {b:1}

對於建立一個對象來講,更推薦使用字面量的方式建立對象(不管性能上仍是可讀性上)。若是使用 new Object()的方式建立對象須要經過做用域鏈一層層找到Object,可是使用字面量就沒這個問題。

new的運算符優先級

function Foo() {
    return this;
}
Foo.getName = function() {
    console.log('1');
}
Foo.prototype.getName = function() {
    console.log('2');
}
複製代碼

15.深淺拷貝

let a = {
    age: 1
}
let b = a;
a.age = 2;
console.log(b.age) //2
複製代碼

若是給一個變量賦值,二者是同一個引用,其中一方改變,另外一方也會相應改變。 當對象裏面的值是簡單數據類型,即不是對象類型的時候,淺拷貝就能解決該問題。

淺拷貝

  • Object.assign
    let a = {
        age: 1
    }
    let b = Object.assign({}, a);
    a.age = 2;
    console.log(b.age)// 1
    複製代碼
  • ...擴展運算符
    let a = {
        age: 1
    }
    b = {...a};
    a.age = 2;
    console.log(b.age);//1
    複製代碼
  • Array.prototype.slice(0) 能夠淺拷貝一個數組

深拷貝

當存在這種狀況,咱們要使用深拷貝

let a = {
    age: 1,
    job: {
        first: 'FE'
    }
}
let b = {...a};
a.job.first = 'native';
console.log(b.job.first)//native
複製代碼
  • JSON.parse(JSON.stringify(object))
let a = {
    age: 1,
    job: {
        first: 'FE'
    }
}
let b = JSON.parse(JSON.stringify(a))
a.job.first = 'native';
console.log(b.job.first)//FE
複製代碼

可是該方法也存在必定的侷限性:

  • 會忽略undefined
  • 不會序列化函數
  • 不能解決循環引用的對象

可是在一般狀況下,複雜數據都是能夠序列化的,因此這個方法能夠解決大部分問題,而且該函數是內置函數中處理深拷貝最快的。

若是存在上述三種狀況能夠使用loadsh的深拷貝函數

若是須要拷貝的對象不包含函數,但存在undefined和循環引用的對象,能夠使用MessageChannel

function structrualClone(obj) {
    return new Promise(resolve => {
        cost {port1, port2} = new MessageChannel();
        port2.onmessage = ev => resolve(ev.data);
        post1.postMessage(obj);
    })
}

var obj = {
    a: 1,
    b: {
        c: b
    }
}
//注意該方法是異步的
//能夠處理undefined和循環對象
const clone = await structrualClone(obj);
複製代碼

16.Promise 對象 async 函數以及 awit 命令

關於Promise

Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。所謂Promise,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。

Promise 對象表明一個異步操做,有三種狀態:pending(進行中)、fulfilled(已成功)和 rejected(已失敗)。只有異步操做的結果,能夠決定當前是哪種狀態,任何其餘操做都沒法改變這個狀態。

特色:

  • 對象的狀態不受外界影響
  • 一旦狀態改變,就不會再變,任什麼時候候均可以獲得這個結果
  • Promise 新建後就會當即執行
const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 異步操做成功 */){
    resolve(value);
  } else {
    reject(error);
  }
})
複製代碼

Promise實例生成之後,能夠用then方法分別指定resolved狀態和rejected狀態的回調函數

promise.then(function(value) {
  // success
}, function(error) {
  // failure
})
複製代碼

then 方法返回的是一個新的Promise實例

Promise.prototype.catch 用於指定發生錯誤時的回調函數,具備「冒泡」性質,會一直向後傳遞,直到被捕獲爲止。也就是說,錯誤老是會被下一個catch語句捕獲

getJSON('/post/1.json').then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {
  // 處理前面三個Promise產生的錯誤
});
複製代碼

catch 方法返回的仍是一個 Promise 對象,所以後面還能夠接着調用 then 方法

關於async 函數以及 awit 命令

async 函數是什麼?一句話,它就是 Generator 函數的語法糖

Generator 函數是一個普通函數,可是有兩個特徵。

  • 1.function關鍵字與函數名之間有一個星號
  • 2.函數體內部使用yield表達式,定義不一樣的內部狀態(yield在英語裏的意思就是「產出」)。
function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();
複製代碼

調用 Generator 函數後,該函數並不執行,返回的也不是函數運行結果,而是一個指向內部狀態的指針對象,一個遍歷器對象(Iterator Object)。

下一步,必須調用遍歷器對象的next方法,使得指針移向下一個狀態。也就是說,每次調用next方法,內部指針就從函數頭部或上一次停下來的地方開始執行,直到遇到下一個yield表達式(或return語句)爲止。換言之,Generator 函數是分段執行的,yield表達式是暫停執行的標記,而next方法能夠恢復執行。

hw.next()
// { value: 'hello', done: false }

hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

hw.next()
// { value: undefined, done: true }
複製代碼

async 特色:

  • async 函數返回一個 Promise 對象,能夠使用 then 方法添加回調函數。當函數執行的時候,一旦遇到 await 就會先返回,等到異步操做完成,再接着執行函數體內後面的語句

  • async 函數內部 return 語句返回的值,會成爲 then 方法回調函數的參數

  • async 函數返回的 Promise 對象,必須等到內部全部 await 命令後面的 Promise 對象執行完,纔會發生狀態改變,除非遇到 return 語句或者拋出錯誤

  • async 函數內部拋出錯誤,會致使返回的 Promise 對象變爲 reject 狀態。拋出的錯誤對象會被 catch 方法回調函數接收到

function timeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint('hello world', 50);
複製代碼

await 命令: await 命令後面是一個 Promise 對象,返回該對象的結果。若是不是 Promise 對象,就直接返回對應的值

async function f() {
  // 等同於
  // return 123;
  return await 123;
}

f().then(v => console.log(v))
// 123
複製代碼

await 命令後面是一個thenable對象(即定義then方法的對象),那麼await會將其等同於 Promise 對象.也就是說就算一個對象不是Promise對象,可是隻要它有then這個方法, await 也會將它等同於Promise對象

使用注意點:

  • await 命令後面的 Promise 對象,運行結果多是 rejected,因此最好把 await 命令放在 try...catch 代碼塊中
  • 多個 await 命令後面的異步操做,若是不存在繼發關係,最好讓它們同時觸發
  • await 命令只能用在 async 函數之中,若是用在普通函數,就會報錯

17.JS引擎執行機制 微任務 宏任務

首選明確兩點:

  • JavaScript 是單線程語言

  • JavaScript 的 Event Loop 是 JS 的執行機制, 也就是事件循環

執行時,將任務分爲兩類:

  • macro-task(宏任務):包括總體代碼script,setTimeout,setInterval

  • micro-task(微任務):Promise,process.nextTick

JS的執行機制是

  • 執行一個宏任務,過程當中若是遇到微任務,就將其放到微任務的【事件隊列】裏(先進先出原則)
  • 當前宏任務執行完成後,會查看微任務的【事件隊列】,並將裏面所有的微任務依次執行完(先進先出原則)
setTimeout(function(){console.log(1);},0);
new Promise(function(resolve){
     console.log(2);
     for(var i = 0; i < 10000; i++){
         i == 99 && resolve();
     }
 }).then(function(){
     console.log(3)
 });
 
 console.log(4);
 
 // 2 4 3 1
複製代碼
async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}
async function async2() {
    console.log('async2');
}
console.log('script start');
setTimeout(function(){
    console.log('setTimeout');
}, 0);
async1();
new Promise(function(resolve){
    console.log('promise1');
    resolve();
}).then(function(){
    console.log('promise2')
})
console.log('script end');
複製代碼

輸出:

script start

async1 start

async2

promise1

script end

async1 end

promise2

setTimeout

18.export 與 export default有什麼區別

export 與 export default 都可用於導出常量、函數、文件、模塊等

  • 在一個文件或模塊中,export、import 能夠有多個,export default 僅有一個

  • 經過 export 方式導出,在導入時要加 { },export default 則不須要

  • 使用 export default命令,爲模塊指定默認輸出,這樣就不須要知道所要加載模塊的變量名; export 加載的時候須要知道加載模塊的變量名

  • export default 命令的本質是將後面的值,賦給 default 變量,因此能夠直接將一個值寫在 export default 以後

19.什麼是內存泄漏,哪些操做會形成內存泄漏

內存泄漏:是指一塊被分配的內存既不能使用,又不能回收,直到瀏覽器進程結束

可能形成內存泄漏的操做:

  • 意外的全局變量
  • 閉包
  • 循環引用
  • 被遺忘的定時器或者回調函數
  • setTimeout 的第一個參數使用字符串而非函數的話,會引起內存泄漏

20.同步和異步的區別,怎麼異步加載 JavaScript

1.同步模式

同步模式,又稱阻塞模式。javascript 在默認狀況下是會阻塞加載的。當前面的 javascript 請求沒有處理和執行完時,會阻止瀏覽器的後續處理

2.異步模式

異步加載又叫非阻塞,瀏覽器在下載執行 js 同時,還會繼續進行後續頁面的處理

如何實現異步加載 JavaScript

  • 1.動態添加 script 標籤

defer屬性和async都是屬於 script 標籤上面的屬性,二者都能實現 JavaScript 的異步加載,不一樣之處在於:

  • 2.defer:defer 會等到 html 加載完畢以後再執行,只支持IE
  • 3.async:async 在異步加載完成的時候就立刻開始執行了

21.AJAX、$.ajax、axios、fetch、superagent

參考另外一篇總結:juejin.im/post/5caed2…

22.js排序算法詳解

各排序算法實現:mp.weixin.qq.com/s/gR0kCPRgQ…

3、瀏覽器和網絡

1.從瀏覽器地址欄輸入url到顯示頁面的步驟

一、瀏覽器的地址欄輸入URL並按下回車。

二、瀏覽器查找當前URL是否存在緩存,並比較緩存是否過時。

三、DNS解析URL對應的IP。

四、根據IP創建TCP鏈接(三次握手)。

五、HTTP發起請求。

六、服務器處理請求,瀏覽器接收HTTP響應。

七、渲染頁面,構建DOM樹。

八、關閉TCP鏈接(四次揮手)

(1) URL

咱們常見的RUL是這樣的:www.baidu.com,這個域名由三部分組成:協議名、域名、端口號,這裏端口是默認因此隱藏。除此以外URL還會包含一些路徑、查詢和其餘片斷,例如:www.tuicool.com/search?kw=�… 咱們最多見的的協議是HTTP協議,除此以外還有加密的HTTPS協議、FTP協議、FILe協議等等。URL的中間部分爲域名或者是IP,以後就是端口號了。一般端口號不常見是由於大部分的都是使用默認端口,如HTTP默認端口80,HTTPS默認端口443。

(2) 緩存

HTTP緩存有多種規則,根據是否須要從新向服務器發起請求來分類,分爲強制緩存,對比緩存。   

  • 強制緩存判斷HTTP首部字段:cache-control,Expires。

    • Expires: 是一個絕對時間,即服務器時間。瀏覽器檢查當前時間,若是還沒到失效時間就直接使用緩存文件。可是該方法存在一個問題:服務器時間與客戶端時間可能不一致。所以該字段已經不多使用。

    • cache-control: cache-control中的max-age保存一個相對時間。例如Cache-Control: max-age = 484200,表示瀏覽器收到文件後,緩存在484200s內均有效。

    • 若是同時存在cache-control和Expires,瀏覽器老是優先使用cache-control。

  • 對比緩存經過HTTP的last-modified,Etag字段進行判斷。

    last-modified是第一次請求資源時,服務器返回的字段,表示最後一次更新的時間。下一次瀏覽器請求資源時就發送if-modified-since字段。服務器用本地Last-modified時間與if-modified-since時間比較,若是不一致則認爲緩存已過時並返回新資源給瀏覽器;若是時間一致則發送304狀態碼,讓瀏覽器繼續使用緩存。   

    Etag:資源的實體標識(哈希字符串),當資源內容更新時,Etag會改變。服務器會判斷Etag是否發生變化,若是變化則返回新資源,不然返回304。

(3) DNS域名解析

咱們知道在地址欄輸入的域名並非最後資源所在的真實位置,域名只是與IP地址的一個映射。網絡服務器的IP地址那麼多,咱們不可能去記一串串的數字,所以域名就產生了,域名解析的過程實際是將域名還原爲IP地址的過程。

  • 首先瀏覽器先檢查本地hosts文件是否有這個網址映射關係,若是有就調用這個IP地址映射,完成域名解析。
  • 若是沒找到則會查找本地DNS解析器緩存,若是查找到則返回。
  • 若是仍是沒有找到則會查找本地DNS服務器,若是查找到則返回。
  • 最後
    • 迭代查詢,按根域服務器 ->頂級域,.cn->第二層域,hb.cn ->子域,www.hb.cn的順序找到IP地址。
    • 或遞歸查詢,按上一級DNS服務器->上上級->....逐級向上查詢找到IP地址。

(4) TCP鏈接

在經過第一步的DNS域名解析後,獲取到了服務器的IP地址,在獲取到IP地址後,便會開始創建一次鏈接,這是由TCP協議完成的,主要經過三次握手進行鏈接。

  • 第一次握手(SYN=1, seq=x):

    客戶端發送一個 TCP 的 SYN 標誌位置1的包,指明客戶端打算鏈接的服務器的端口,以及初始序號 X,保存在包頭的序列號(Sequence Number)字段裏。

    發送完畢後,客戶端進入 SYN_SEND 狀態。

  • 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):

    服務器發回確認包(ACK)應答。即 SYN 標誌位和 ACK 標誌位均爲1。服務器端選擇本身 ISN 序列號,放到 Seq 域裏,同時將確認序號(Acknowledgement Number)設置爲客戶的 ISN 加1,即X+1。

    發送完畢後,服務器端進入 SYN_RCVD 狀態。

  • 第三次握手(ACK=1,ACKnum=y+1)

    客戶端再次發送確認包(ACK),SYN 標誌位爲0,ACK 標誌位爲1,而且把服務器發來 ACK 的序號字段+1,放在肯定字段中發送給對方,而且在數據段放寫ISN的+1。

    發送完畢後,客戶端進入 ESTABLISHED 狀態,當服務器端接收到這個包時,也進入 ESTABLISHED 狀態,TCP 握手結束。

(5) 瀏覽器向服務器發送HTTP請求

完整的HTTP請求包含請求起始行、請求頭部、請求主體三部分。

(6) 瀏覽器接收響應

服務器在收到瀏覽器發送的HTTP請求以後,會將收到的HTTP報文封裝成HTTP的Request對象,並經過不一樣的Web服務器進行處理,處理完的結果以HTTP的Response對象返回,主要包括狀態碼,響應頭,響應報文三個部分。

  • 狀態碼主要包括如下部分
    • 1xx:指示信息–表示請求已接收,繼續處理。
    • 2xx:成功–表示請求已被成功接收、理解、接受。
    • 3xx:重定向–要完成請求必須進行更進一步的操做。
    • 4xx:客戶端錯誤–請求有語法錯誤或請求沒法實現。
    • 5xx:服務器端錯誤–服務器未能實現合法的請求。
  • 響應頭主要由Cache-Control、 Connection、Date、Pragma等組成。
  • 響應體爲服務器返回給瀏覽器的信息,主要由HTML,css,js,圖片文件組成。

(7) 頁面渲染

若是說響應的內容是HTML文檔的話,就須要瀏覽器進行解析渲染呈現給用戶。

整個過程涉及兩個方面:解析和渲染。

在渲染頁面以前,須要構建DOM樹和CSSOM樹。

在瀏覽器還沒接收到完整的 HTML文件時,它就開始渲染頁面了,在遇到外部鏈入的腳本標籤或樣式標籤或圖片時,會再次發送 HTTP 請求重複上述的步驟。在收到CSS文件後會對已經渲染的頁面從新渲染,加入它們應有的樣式,圖片文件加載完馬上顯示在相應位置。在這一過程當中可能會觸發頁面的重繪或重排。這裏就涉及了兩個重要概念:Reflow和Repaint

(8) 關閉TCP鏈接或繼續保持鏈接

經過四次揮手關閉鏈接(FIN ACK, ACK, FIN ACK, ACK)。

  • 第一次揮手(FIN=1,seq=x)

    假設客戶端想要關閉鏈接,客戶端發送一個 FIN 標誌位置爲1的包,表示本身已經沒有數據能夠發送了,可是仍然能夠接受數據。

    發送完畢後,客戶端進入 FIN_WAIT_1 狀態。

  • 第二次揮手(ACK=1,ACKnum=x+1)

    服務器端確認客戶端的 FIN 包,發送一個確認包,代表本身接受到了客戶端關閉鏈接的請求,但尚未準備好關閉鏈接。

    發送完畢後,服務器端進入 CLOSE_WAIT 狀態,客戶端接收到這個確認包以後,進入 FIN_WAIT_2 狀態,等待服務器端關閉鏈接。

  • 第三次揮手(FIN=1,seq=y)

    服務器端準備好關閉鏈接時,向客戶端發送結束鏈接請求,FIN 置爲1。

    發送完畢後,服務器端進入 LAST_ACK 狀態,等待來自客戶端的最後一個ACK。

  • 第四次揮手(ACK=1,ACKnum=y+1)

    客戶端接收到來自服務器端的關閉請求,發送一個確認包,並進入 TIME_WAIT狀態,等待可能出現的要求重傳的 ACK 包。

    服務器端接收到這個確認包以後,關閉鏈接,進入 CLOSED 狀態。

    客戶端等待了某個固定時間(兩個最大段生命週期,2MSL,2 Maximum Segment Lifetime)以後,沒有收到服務器端的 ACK ,認爲服務器端已經正常關閉鏈接,因而本身也關閉鏈接,進入 CLOSED 狀態。

2.HTTP狀態碼及其含義

1XX:信息狀態碼

100 Continue 繼續,通常在發送post請求時,已發送了http header以後服務端將返回此信息,表示確認,以後發送具體參數信息

2XX:成功狀態碼

200 OK 正常返回信息

201 Created 請求成功而且服務器建立了新的資源

202 Accepted 服務器已接受請求,但還沒有處理

3XX:重定向

301 Moved Permanently 請求的網頁已永久移動到新位置。

302 Found 臨時性重定向。

303 See Other 臨時性重定向,且老是使用 GET 請求新的 URI。

304 Not Modified 自從上次請求後,請求的網頁未修改過。

4XX:客戶端錯誤

400 Bad Request 服務器沒法理解請求的格式,客戶端不該當嘗試再次使用相同的內容發起請求。

401 Unauthorized 請求未受權。

403 Forbidden 禁止訪問。

404 Not Found 找不到如何與 URI 相匹配的資源。

408 (請求超時) 服務器等候請求時發生超時

5XX: 服務器錯誤

500 Internal Server Error 最多見的服務器端錯誤。

501 Internal Server Error 服務器遇到一個錯誤,使其沒法對請求提供服務

502 (錯誤網關) 服務器做爲網關或代理,從上游服務器收到無效響應

503 Service Unavailable 服務器端暫時沒法處理請求(多是過載或維護)。

3.跨域問題的產生,怎麼解決它

因爲瀏覽器的 同源策略,在出現 域名、端口、協議有一種不一致時,就會出現跨域,屬於瀏覽器的一種安全限制。

解決跨域問題有不少種方式,經常使用的就是如下幾種:

(1).jsonp 跨域

動態建立script,再請求一個帶參網址實現跨域通訊.缺點就是隻能實現 get 一種請求

(2).document.domain + iframe跨域

兩個頁面都經過js強制設置document.domain爲基礎主域,就實現了同域.可是僅限主域相同,子域不一樣的跨域應用場景

(3).跨域資源共享(CORS)

只服務端設置Access-Control-Allow-Origin便可,前端無須設置,若要帶cookie請求:先後端都須要設置

詳細參考:www.ruanyifeng.com/blog/2016/0…

(4).nginx反向代理接口跨域

同源策略是瀏覽器的安全策略,不是HTTP協議的一部分。服務器端調用HTTP接口只是使用HTTP協議,不會執行JS腳本,不須要同源策略,也就不存在跨越問題

5.WebSocket協議跨域

4.前端性能優化

參考 blog.csdn.net/qfkfw/artic…

5.常見web安全及防禦原理

(1).sql注入原理

就是經過把SQL命令插入到Web表單遞交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令

總的來講有如下幾點

永遠不要信任用戶的輸入,要對用戶的輸入進行校驗,能夠經過正則表達式,或限制長度,對單引號和雙"-"進行轉換等 永遠不要使用動態拼裝SQL,能夠使用參數化的SQL或者直接使用存儲過程進行數據查詢存取 永遠不要使用管理員權限的數據庫鏈接,爲每一個應用使用單獨的權限有限的數據庫鏈接 不要把機密信息明文存放,請加密或者hash掉密碼和敏感的信息

(2).XSS原理及防範(Cross Site Scripting,跨站腳本攻擊)

  • 什麼是XSS

    XSS 全稱「跨站腳本」,是注入攻擊的一種。其特色是不對服務器端形成任何傷害,而是經過一些正常的站內交互途徑,例如發佈評論,提交含有 JavaScript 的內容文本。這時服務器端若是沒有過濾或轉義掉這些腳本,做爲內容發佈到了頁面上,其餘用戶訪問這個頁面的時候就會運行這些腳本。

    運行預期以外的腳本帶來的後果有不少中,可能只是簡單的惡做劇——一個關不掉的窗口:

    while (true) {
          alert("你關不掉我~");
      }
    複製代碼
  • 如何防護 XSS 攻擊?

    理論上,全部可輸入的地方沒有對輸入數據進行處理的話,都會存在XSS漏洞,漏洞的危害取決於攻擊代碼的威力,攻擊代碼也不侷限於 script。防護 XSS 攻擊最簡單直接的方法,就是過濾用戶的輸入。

    若是不須要用戶輸入 HTML,能夠直接對用戶的輸入進行 HTML escape 。下面一小段腳本:

    <script>window.location.href=」http://www.baidu.com」;</script>
    複製代碼

    通過 escape 以後就成了:

    &lt;script&gt;window.location.href=&quot;http://www.baidu.com&quot;&lt;/script&gt;
    複製代碼

    它如今會像普通文本同樣顯示出來,變得無毒無害,不能執行了。

    當咱們須要用戶輸入 HTML 的時候,須要對用戶輸入的內容作更加當心細緻的處理。僅僅粗暴地去掉 script 標籤是沒有用的,任何一個合法 HTML 標籤均可以添加 onclick 一類的事件屬性來執行 JavaScript。更好的方法多是,將用戶的輸入使用 HTML 解析庫進行解析,獲取其中的數據。而後根據用戶原有的標籤屬性,從新構建 HTML 元素樹。構建的過程當中,全部的標籤、屬性都只從白名單中拿取。

(3) CSRF原理及防範(Cross-site request forgery,跨站請求僞造)

  • 什麼是CSRF?

    CSRF(XSRF) 顧名思義,是僞造請求,冒充用戶在站內的正常操做。

    例如,一論壇網站的發貼是經過 GET 請求訪問,點擊發貼以後 JS 把發貼內容拼接成目標 URL 並訪問:

    http://example.com/bbs/create_post.php?title=標題&content=內容
    複製代碼

    那麼,咱們只須要在論壇中發一帖,包含一連接:

    http://example.com/bbs/create_post.php?title=我是腦殘&content=哈哈
    複製代碼

    只要有用戶點擊了這個連接,那麼他們的賬戶就會在不知情的狀況下發布了這一帖子。可能這只是個惡做劇,可是既然發貼的請求能夠僞造,那麼刪帖、轉賬、改密碼、發郵件全均可以僞造。

  • 如何防範 CSRF 攻擊?

    • 關鍵操做只接受 POST 請求

    • 驗證碼

      CSRF 攻擊的過程,每每是在用戶不知情的狀況下構造網絡請求。因此若是使用驗證碼,那麼每次操做都須要用戶進行互動,從而簡單有效的防護了CSRF攻擊。

      可是若是你在一個網站做出任何舉動都要輸入驗證碼會嚴重影響用戶體驗,因此驗證碼通常只出如今特殊操做裏面,或者在註冊時候使用。

    • 檢測 Referer

      常見的互聯網頁面與頁面之間是存在聯繫的,好比你在 www.baidu.com 應該是找不到通往www.google.com 的連接的,再好比你在論壇留言,那麼無論你留言後重定向到哪裏去了,以前的那個網址必定會包含留言的輸入框,這個以前的網址就會保留在新頁面頭文件的 Referer 中

      經過檢查 Referer 的值,咱們就能夠判斷這個請求是合法的仍是非法的,可是問題出在服務器不是任什麼時候候都能接受到 Referer 的值,因此 Referer Check 通常用於監控 CSRF 攻擊的發生,而不用來抵禦攻擊。

    • Token

      目前主流的作法是使用 Token 抵禦 CSRF 攻擊。下面經過分析 CSRF 攻擊來理解爲何 Token 可以有效

      CSRF 攻擊要成功的條件在於攻擊者可以預測全部的參數從而構造出合法的請求。因此根據不可預測性原則,咱們能夠對參數進行加密從而防止 CSRF 攻擊。

      另外一個更通用的作法是保持原有參數不變,另外添加一個參數 Token,其值是隨機的。這樣攻擊者由於不知道 Token 而沒法構造出合法的請求進行攻擊。

      【Token 使用原則】

      • Token 要足夠隨機————只有這樣纔算不可預測
      • Token 是一次性的,即每次請求成功後要更新Token————這樣能夠增長攻擊難度,增長預測難度
      • Token 要注意保密性————敏感操做使用 post,防止 Token 出如今 URL 中

      注意:過濾用戶輸入的內容不能阻擋 csrf,咱們須要作的是過濾請求的來源。

(4) XSS與CSRF有什麼區別嗎?

XSS(跨站腳本攻擊——Cascading Style Sheets,爲不和層疊樣式表 縮寫混淆,故將跨站腳本攻擊縮寫爲XSS )是獲取信息,不須要提早知道其餘用戶頁面的代碼和數據包。

CSRF(跨站請求僞造——Cross-site request forgery)是代替用戶完成指定的動做,須要知道其餘用戶頁面的代碼和數據包。要完成一次CSRF攻擊,受害者必須依次完成兩個步驟 登陸受信任網站A,並在本地生成Cookie 在不登出A的狀況下,訪問危險網站B

6. http與https

(1) http有什麼特色

是互聯網上應用最爲普遍的一種網絡協議,是一個客戶端和服務器端請求和應答的標準(TCP),用於從WWW服務器傳輸超文本到本地瀏覽器的傳輸協議,它能夠使瀏覽器更加高效,使網絡傳輸減小.HTTP 協議構建於 TCP/IP 協議之上,是一個應用層協議,默認端口號是 80

  • 簡單快速:客戶向服務器請求服務時,只需傳送請求方法和路徑

  • 靈活:HTTP容許傳輸任意類型的數據對象。正在傳輸的類型由 Content-Type 加以標記

  • 無狀態:HTTP協議是無狀態協議( Cookie 的出現)

  • 無鏈接:無鏈接的含義是限制每次鏈接只處理一個請求。服務器處理完客戶的請求,並收到客戶的應答後,即斷開鏈接 (深刻-持久鏈接、管線化)

    • 若是客戶端瀏覽器支持 Keep-Alive ,那麼就在HTTP請求頭中添加一個字段 Connection: Keep-Alive,當服務器收到附帶有 Connection:Keep-Alive的請求時,它也會在響應頭中添加一個一樣的字段來使用 Keep-Alive 。這樣一來,客戶端和服務器之間的HTTP鏈接就會被保持,不會斷開(超過 Keep-Alive 規定的時間,意外斷電等狀況除外),當客戶端發送另一個請求時,就使用這條已經創建的鏈接。

    • 在 HTTP 1.1 版本中,默認狀況下全部鏈接都被保持,若是加入 "Connection: close" 才關閉。目前大部分瀏覽器都使用 HTTP 1.1 協議,也就是說默認都會發起 Keep-Alive 的鏈接請求了,因此是否能完成一個完整的 Keep-Alive 鏈接就看服務器設置狀況。

    • HTTP Keep-Alive 簡單說就是保持當前的TCP鏈接,避免了從新創建鏈接。

    • HTTP 長鏈接不可能一直保持,例如 Keep-Alive: timeout=5, max=100,表示這個TCP通道能夠保持5秒,max=100,表示這個長鏈接最多接收100次請求就斷開。

    • HTTP 是一個無狀態協議,這意味着每一個請求都是獨立的,Keep-Alive沒能改變這個結果。另外,Keep-Alive也不能保證客戶端和服務器之間的鏈接必定是活躍的,在HTTP1.1版本中也如此。惟一能保證的就是當鏈接被關閉時你能獲得一個通知,因此不該該讓程序依賴於 Keep-Alive 的保持鏈接特性,不然會有意想不到的後果。

    • 使用長鏈接以後,客戶端、服務端怎麼知道本次傳輸結束呢?兩部分:1. 判斷傳輸數據是否達到了Content-Length 指示的大小;2. 動態生成的文件沒有 Content-Length ,它是分塊傳輸(chunked),這時候就要根據 chunked 編碼來判斷,chunked 編碼的數據在最後有一個空 chunked 塊,代表本次傳輸數據結束。

(2) https有什麼特色

是以安全爲目標的HTTP通道,簡單講是 HTTP 的安全版,即 HTTP 下加入 SSL 層(Secure Sockets Layer),HTTPS 的安全基礎是 SSL ,所以加密的詳細內容就須要 SSL

HTTPS加密、加密、及驗證過程,以下圖所示:

(3) http和https協議有什麼區別

  • https協議須要到ca申請證書,通常免費證書較少,於是須要必定費用

  • http 是超文本傳輸協議,信息是明文傳輸,https 則是具備安全性的 ssl 加密傳輸協議

  • http 和 https 使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是 80 ,後者是 443

  • http 的鏈接很簡單,是無狀態的;HTTPS 協議是由 SSL+HTTP 協議構建的可進行加密傳輸、身份認證的網絡協議,比 http 協議安全

  • HTTP使用TCP三次握手創建鏈接,客戶端和服務器須要交換3個包(可參考 HTTP服務的七層架構技術解析及運用 user-gold-cdn.xitu.io/2019/4/17/1…)

(4) https的工做原理

一、客戶端發起HTTPS請求

這個沒什麼好說的,就是用戶在瀏覽器裏輸入一個https網址,而後鏈接到server的443端口。

二、服務端的配置

採用HTTPS協議的服務器必需要有一套數字證書,能夠本身製做,也能夠向組織申請,區別就是本身頒發的證書須要客戶端驗證經過,才能夠繼續訪問,而使用受信任的公司申請的證書則不會彈出提示頁面(startssl就是個不錯的選擇,有1年的免費服務)。

這套證書其實就是一對公鑰和私鑰,若是對公鑰和私鑰不太理解,能夠想象成一把鑰匙和一個鎖頭,只是全世界只有你一我的有這把鑰匙,你能夠把鎖頭給別人,別人能夠用這個鎖把重要的東西鎖起來,而後發給你,由於只有你一我的有這把鑰匙,因此只有你才能看到被這把鎖鎖起來的東西。

三、傳送證書

這個證書其實就是公鑰,只是包含了不少信息,如證書的頒發機構,過時時間等等。

四、客戶端解析證書

這部分工做是有客戶端的TLS來完成的,首先會驗證公鑰是否有效,好比頒發機構,過時時間等等,若是發現異常,則會彈出一個警告框,提示證書存在問題。

若是證書沒有問題,那麼就生成一個隨機值,而後用證書對該隨機值進行加密,就好像上面說的,把隨機值用鎖頭鎖起來,這樣除非有鑰匙,否則看不到被鎖住的內容。

五、傳送加密信息

這部分傳送的是用證書加密後的隨機值,目的就是讓服務端獲得這個隨機值,之後客戶端和服務端的通訊就能夠經過這個隨機值來進行加密解密了。

六、服務段解密信息

服務端用私鑰解密後,獲得了客戶端傳過來的隨機值(私鑰),而後把內容經過該值進行對稱加密,所謂對稱加密就是,將信息和私鑰經過某種算法混合在一塊兒,這樣除非知道私鑰,否則沒法獲取內容,而正好客戶端和服務端都知道這個私鑰,因此只要加密算法夠彪悍,私鑰夠複雜,數據就夠安全。

七、傳輸加密後的信息

這部分信息是服務段用私鑰加密後的信息,能夠在客戶端被還原。

八、客戶端解密信息

客戶端用以前生成的私鑰解密服務段傳過來的信息,因而獲取瞭解密後的內容,整個過程第三方即便監聽到了數據,也一籌莫展。

7. 網絡分層模型——TCP/IP模型和OSI模型

(1) TCP/IP模型

TCP/IP模型分爲四層:

  • 應用層(Application)
  • 傳輸層(Host-to-Host Transport)
  • 互聯網層(Internet)
  • 網絡接口層(Network Interface)

在TCP/IP模型中並不包含物理層。另外,兩個重要的協議ARP(Address Resolution Protocol,地址解析協議)和RARP(Reverse Address Resolution Protocol,反向地址轉換協議),在OSI模型中通常被認爲是在位於第二層數據鏈路層和第三層網絡層之間,而在TCP/IP模型中則位於網絡接口層。

(2)OSI模型

詳細描述參考: juejin.im/post/5a98e1…

8. IE瀏覽器兼容問題

參考另外一篇總結:juejin.im/post/5cb822…

相關文章
相關標籤/搜索