前端面試題整理

參考文章

html

html5語義化和新特性

  • 語義化讓網頁結構更加清晰,便於瀏覽器、搜索引擎的解析,便於閱讀維護。javascript

  • 語義化標籤php

    • Header main footer nav article aside detailes dialog
  • 加強表單css

    • Color date email number range search url time tel month
  • 新增的表單屬性html

    • Placehoder required min max step autofoucs
  • 視頻和音頻前端

    • audio video
  • canvas/svg繪圖vue

    • canvas標籤是圖形容器,必須使用腳原本繪製圖形
    • svg是可伸縮的矢量圖
  • 地理位置html5

  • 拖放Apijava

  • Web Workernode

    • 運行在後臺的js腳本,獨立於其餘腳本,不影響頁面性能
  • Web Storagereact

    • localStorage: 沒有時間限制的數據存儲
    • sessionStorage: 針對一個session的數據存儲,當用戶關閉瀏覽器窗口後數據會被刪除
  • webSocket

瀏覽器的標準模式和怪異模式/怪異盒模型

  • 現代瀏覽器通常都有兩種渲染模式 標準模式怪異模式,
  • 在標準模式下文檔按照w3c的規範進行解析和渲染
  • 在怪異模式下文檔按照瀏覽器本身的方式進行解析和渲染
  • 好比, 標準模式下盒模型的總寬度等於左右margin + 左右padding + 左右的border + 內容的寬度
  • 而在怪異模式下內容的寬度包含了padding和border
  • 在標準模式下可使用box-sizing把盒模型變成怪異盒模型

html和xhtml的區別

  • html是超文本標記語言,是一種語法比較鬆散的標記語言,語法要求也不嚴格。好比說,標籤名大小寫混寫,屬性名單雙引號均可以,標籤能夠不閉合
  • xhtml是可擴展的標記語言,能夠說是html的嚴格模式,好比標籤名必須小寫,屬性必須加引號,引號必須是雙引號,標籤要閉合等等。

使用data-*的好處

  • data屬性是h5新增的一種用於保存自定義數據的屬性,老是以data-出現。
  • 好處是能夠儲存些不須要在瀏覽器上展現但又重要的信息,好比文章的ID
  • 用js能夠很方便的去讀寫這些屬性,好比dataset getAttribute setAttribute data()

canvas

canavs是h5新增一種用戶繪製圖形的容器標籤,經過js繪製,經常使用於動畫,遊戲頁面,數據可視化。

定位的寫法

position: absolute;/*絕對定位*/
position: relative; /*相對定位*/
position: flexd; /*固定定位* / 複製代碼

CSS/js放置的位置和緣由

什麼是漸進式渲染

指瀏覽器不用等待全部頁面資源都渲染好以後再呈現給用戶看,而是邊下載邊渲染,因此用戶打開一個網頁的時候每每不能第一時間看到全部的內容,可是可以看到一個大概的樣子,後續的內容瀏覽器會慢慢補上造成一個完整的頁面。

  • 解決什麼問題: 爲了解決js加載時間的問題。
  • 怎麼實現 服務器端渲染SSR,流行的vue,react都有SSR解決方案。

模板引擎

是一種將業務邏輯層和表現層分離,將規定格式的模板代碼轉化爲業務數據的實現

meta viewport原理

前端頁面有哪三層構成,分別是什麼?做用是什麼?

  • 結構層
    • 由html/xhtml之類的標記語言來建立,對網頁內容的語義作出描述
  • 表示層
    • 由css負責建立,對網頁如何顯示內容作出定義
  • 行爲層
    • 有JavaScript負責。對網頁內容應該如何對事件作出反應

網頁驗證碼有什麼做用。

  • 區分是計算機程序仍是人,防止惡意攻擊
  • 防止黑客針對某個特定用戶以特定程序進行暴力破解

漸進加強和優雅降級

  • 漸進加強一開始保證最基本的功能,再改進和追加功能
  • 優雅降級一開始就構建完整的功能,在針對低版本瀏覽器進行兼容

區別

優雅降級從複雜開始,漸進加強則從一個基礎的版本開始,並不斷擴充。

DOM和BOM

  • DOM是文檔對象模型,是爲了操做文檔出現的API,document是其中的一個對象
  • DOM是瀏覽器對象模型,是爲了操做瀏覽器出現的API,window是其中的一個對象

css

解釋一下"::before"和":after"中的雙冒號和單冒號的區別

  • 雙冒號表示僞元素,單冒號表示僞類

頁面導入樣式時使用link和@import的區別?

  • Link 屬於 html 標籤,而@import 是 CSS 中提供的

  • 在頁面加載的時候,link會同時被加載,而@import引用的CSS會在頁面加載完成後纔會加載引用的CSS

  • @import只有在ie5以上才能夠被識別,而link是html標籤,不存在瀏覽器兼容性問題

  • link引入樣式的權重大於@import的引用(@import 是將引用的樣式導入到當前的頁面中)

CSS 清除浮動的幾種方法: clear:both;

  • 在浮動的盒子下面再放一個標籤,使用 clear:both;來清除浮動

  • 使用 overflow 清除浮動, 找到浮動盒子的父元素,給父元素添加overflow:hidden;屬性

  • .clearfix:after {
        content:"";
        height:0;
        line-height:0;
        display:block;
        clear:both;
        visibility:hidden;
    }
    // 兼容IE6
    .clearfix {
      zoom: 1;
    }
    複製代碼

CSS 選擇符有哪些?哪些屬性能夠繼承?優先級算法如何計算? CSS3 新增僞類有那些?

1.id選擇器( # myid)
2.類選擇器(.myclassname)
3.標籤選擇器(div, h1, p)
4.相鄰選擇器(h1 + p)
5.子選擇器(ul < li)
6.後代選擇器(li a)
7.通配符選擇器( * )
8.屬性選擇器(a[rel = "external"])
9.僞類選擇器(a: hover, li: nth-child)

*   可繼承: font-size font-family color, UL LI DL DD DT;
*   不可繼承 :border padding margin width height ;
*   優先級就近原則,樣式定義最近者爲準;
*   載入樣式以最後載入的定位爲準;

優先級爲:
!important >  id > class > tag  important 比 內聯優先級高

CSS3新增僞類舉例:
p:first-of-type 選擇屬於其父元素的首個 <p> 元素的每一個 <p> 元素。
p:last-of-type  選擇屬於其父元素的最後 <p> 元素的每一個 <p> 元素。
p:only-of-type  選擇屬於其父元素惟一的 <p> 元素的每一個 <p> 元素。
p:only-child    選擇屬於其父元素的惟一子元素的每一個 <p> 元素。
p:nth-child(2)  選擇屬於其父元素的第二個子元素的每一個 <p> 元素。
:enabled、:disabled 控制表單控件的禁用狀態。
:checked,單選框或複選框被選中。
複製代碼

行內元素和塊級元素的具體區別是什麼?行內元素的padding和margin可設置嗎?

  • 塊級元素(block)特性:

    • 老是獨佔一行,表現爲另起一行開始,並且其後的元素也必須另起一行顯示;
    • 寬度(width)、高度(height)、內邊距(padding)和外邊距(margin)均可控制;
  • 內聯元素(inline)特性:

    • 和相鄰的內聯元素在同一行;
    • 寬度(width)、高度(height)、內邊距的 top/bottom(padding-top/padding-bottom)和外邊距的 top/bottom(margin-top/margin-bottom)都不可改變(也就是 padding 和 margin 的 left 和 right 是能夠設置的),就是裏面文字或圖片的大小。

inline-block元素有哪些?

  • <input> 、<img> 、<button> 、<texterea> 、<label>。

如何垂直居中一個元素?

  • 方法一:絕對定位居中(原始版之已知元素的高寬)
.content {
    width: 200px;
    height: 200px;
    background-color: #6699ff;
    position: absolute; /*父元素須要相對定位*/
    top: 50%;
    left: 50%;
    margin-top: -100px; /*設爲高度的1/2*/
    margin-left: -100px; /*設爲寬度的1/2*/
}
複製代碼
  • 方法二:絕對定位居中(改進版之一未知元素的高寬)
.content {
    width: 200px;
    height: 200px;
    background-color: #6699ff;
    position: absolute; /*父元素須要相對定位*/
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%); /*在水平和垂直方向上各偏移-50%*/
}
複製代碼
  • 方法三:絕對定位居中(改進版之二未知元素的高寬)
.content {
    width: 200px;
    height: 200px;
    background-color: #6699ff;
    margin: auto; /*很關鍵的一步*/
    position: absolute; /*父元素須要相對定位*/
    left: 0;
    top: 0;
    right: 0;
    bottom: 0; /*讓四個定位屬性都爲0*/
}
複製代碼
  • 方法四:flex 佈局居中
body {
  display: flex; /*設置外層盒子display爲flex*/
  align-items: center; /*設置內層盒子的垂直居中*/
  justify-content: center; /*設置內層盒子的水平居中*/
  .content {
    width: 200px;
    height: 200px;
    background-color: #6699ff;
  }
}


複製代碼

垂直居中img

.content {
   /* img的容器設置以下 */
   display: table-cell; 
   text-align: center;
   vertical-align: middle;
}
複製代碼

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 就是頁面上的一個獨立容器,容器裏面的子元素不會影響外面元素。

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

span {
  width: 0;
  heigh: 0;
  border-top: 40px solid transparent;
  border-left: 40px solid transparent;
  border-right: 40px solid transparent;
  border-bottom: 40px solid #ff0000;
}
複製代碼

Sass、LESS 是什麼?爲何要使用他們?

  • 他們是CSS預處理器。是 CSS 上的一種抽象層。他們是一種特殊的語法/語言編譯成 CSS。

  • 爲何要使用它們?

    • 結構清晰,便於擴展。
    • 能夠方便地屏蔽瀏覽器私有語法差別。這個不用多說,封裝對瀏覽器語法差別的重複處理,減小無心義的機械勞動。
    • 能夠輕鬆實現多重繼承。
    • 徹底兼容 CSS 代碼,能夠方便地應用到老項目中。LESS 只是在 CSS 語法上作了擴展,因此老的 CSS 代碼也能夠與 LESS 代碼一同編譯。

css sprite(精靈) 是什麼,有什麼優缺點

  • 概念:

    將多個小圖片拼接到一個圖片中。經過 background-position 和元素尺寸調節須要顯示的背景圖案。

  • 優勢:

    • 減小 HTTP 請求數,極大地提升頁面加載速度。
    • 增長圖片信息重複度,提升壓縮比,減小圖片大小。
    • 更換風格方便,只需在一張或幾張圖片上修改顏色或樣式便可實現。
  • 缺點:

    • 圖片合併麻煩。
    • 維護麻煩,修改一個圖片可能須要重新佈局整個圖片,樣式

移動端 1px 像素問題及解決辦法

  • 媒體查詢利用設備像素比縮放,設置小數像素;
    • 優勢:簡單,好理解
    • 缺點:兼容性差,目前之餘IOS8+才支持,在IOS7及其如下、安卓系統都是顯示0px。

IOS8+下已經支持帶小數的px值,media query 對應 devicePixelRatio 有個查詢值 -webkit-min-device-pixel-ratio;

.border { border: 1px solid #999 }
@media screen and (-webkit-min-device-pixel-ratio: 2) {
  .border { border: 0.5px solid #999 }
}

@media screen and (-webkit-min-device-pixel-ratio: 3) {
  .border { border: 0.333333px solid #999 }
}
複製代碼
<body><div id="main" style="border: 1px solid #000000;"></div></body>
<script type="text/javascript"> if (window.devicePixelRatio && devicePixelRatio >= 2) { var main = document.getElementById('main'); main.style.border = '.5px solid #000000'; } </script>
複製代碼
  • viewport + rem
    • 利用viewport + rem + js 動態的修改頁面的縮放比例
    • 適合新項目,老項目可能要涉及到較多的改動。
<meta name="viewport" id="WebViewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
複製代碼
*var* viewport = document.querySelector("meta[name=viewport]")
if (window.devicePixelRatio == 1) {
  viewport.setAttribute('content', 'width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no')
} 
if (window.devicePixelRatio == 2) {
  viewport.setAttribute('content', 'width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no')
} 
if (window.devicePixelRatio == 3) {
  viewport.setAttribute('content', 'width=device-width, initial-scale=0.333333333, maximum-scale=0.333333333, minimum-scale=0.333333333, user-scalable=no')
} 
*var* docEl = document.documentElement;
*var* fontsize = 10 * (docEl.clientWidth / 320) + 'px';
docEl.style.fontSize = fontsize;
複製代碼
  • box-shadow
    • 利用陰影也能夠實現,優勢是沒有圓角問題,缺點是顏色很差控制
div {
	-webkit-box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.5);
}
複製代碼
  • 媒體查詢 + transfrom(推薦)
/* 2倍屏 */
@media only screen and (-webkit-min-device-pixel-ratio: 2.0) {
    .border-bottom::after {
        -webkit-transform: scaleY(0.5);
        transform: scaleY(0.5);
    }
}
/* 3倍屏 */
@media only screen and (-webkit-min-device-pixel-ratio: 3.0) {
    .border-bottom::after {
        -webkit-transform: scaleY(0.33);
        transform: scaleY(0.33);
    }
}
複製代碼
  • transform: scale(0.5) 方案 - 推薦: 很靈活
div {
  height:1px;
  background:#000;
  -webkit-transform: scaleY(0.5);
  -webkit-transform-origin:0 0;
  overflow: hidden;
}
複製代碼
  • 其餘參考

移動端 1px 像素問題及解決辦法

常見的CSS佈局

  • 單列布局

  • 兩列自適應佈局

  • 聖飛佈局和雙飛翼佈局

  • flxd佈局

CSS3 彈性盒子模型

  • 彈性盒子是 CSS3 的一種新的佈局模式。

  • CSS3 彈性盒( Flexible Box 或 flexbox),是一種當頁面須要適應不一樣的屏幕大小以及設備類型時確保元素擁有恰當的行爲的佈局方式。

  • 引入彈性盒佈局模型的目的是提供一種更加有效的方式來對一個容器中的子元素進行排列、對齊和分配空白空間。

base64:

base64 是網絡上最多見的用於傳輸 8Bit 字節代碼的編碼方式之一,要求把每三個 8Bit 的字節轉換爲四個 6Bit 的字節,Base64 是網絡上最多見的用於傳輸 8Bit 字節代碼的編碼方式之一。
通俗點講:將資源本來二進制形式轉成以 64 個字符基本單位,所組成的一串字符串。
好比一張圖片轉成 base64 編碼後就像這樣,圖片直接以 base64 形式嵌入文件中(很長沒截完):

- 生成 base64 編碼:
圖片生成 base64 能夠用一些工具,如在線工具,但在項目中這樣一個圖片這樣生成是挺繁瑣。
特別說下,webpack 中的 url-loader 能夠完成這個工做,能夠對限制大小的圖片進行 base64 的轉換,很是方便。

- 優勢:
base64 的圖片會隨着 html 或者 css 一塊兒下載到瀏覽器,減小了請求.
可避免跨域問題

- 缺點:
老東西(低版本)的 IE 瀏覽器不兼容。
體積會比原來的圖片大一點。
css 中過多使用 base64 圖片會使得 css 過大,不利於 css 的加載。

- 適用場景:
應用於小的圖片幾 k 的,太大的圖片會轉換後的大小太大,得不償失。
用於一些 css sprites 不利處理的小圖片,如一些能夠經過 background-repeat 平鋪來作成背景的圖片
複製代碼

對偏移、捲曲(捲起)、可視的理解

偏移

offsetWidth  width + padding + border
offsetHeight height + padding + border
offsetLeft
offsetTop
offsetParent
注意:沒有offsetRight和offsetBottom
************************************************************************************************

捲曲
scrollWidth  width + padding
scrollHeight  當內部的內容溢出盒子的時候, 頂邊框的底部,計算到內容的底部;若是內容沒有溢出盒子,計算方式爲盒子內部的真實高度(邊框到邊框)
scrollLeft   這個scroll系列屬性不是隻讀的
scrollTop
scroll()

此函數能夠獲取捲曲的高度和捲曲的寬度
function myScroll() {
  return {
   top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0,
   left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0
  };
}
滾動滾動條的時候觸發事件
box(window).onscroll = function () {}

************************************************************************************************

可視
clientWidth  獲取的是元素內部的真實寬度 width + padding
clientHeight 邊框之間的高度
clientLeft  至關於左邊框的寬度 若是元素包含了滾動條,而且滾動條顯示在元素的左側。這時,clientLeft屬性會包含滾動條的寬度17px
clientTop   至關於頂邊框的寬度
client()

此函數能夠獲取瀏覽器可視區域的寬高
function myClient() {
  return {
    wid: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || 0,
    heit: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0
  };
}
\----------------------------------------------------------------------------------------------
@offsetHeight和style.height的區別
demo.style.height只能獲取行內樣式,若是樣式寫到了其餘地方,甚至根本就沒寫,便沒法獲取
style.height是字符串(並且帶單位),offsetHeight是數值
demo.style.height能夠設置行內樣式,offsetHeight是隻讀屬性
所以,通常用demo.offsetHeight來獲取某元素的真實寬度/高度,用style.height來設置寬度/高度
\----------------------------------------------------------------------------------------------
@offsetLeft和style.left的區別
1、style.left只能獲取行內樣式
2、offsetLeft只讀,style.left可讀可寫
3、offsetLeft是數值,style.left是字符串而且有單位px
4、若是沒有加定位,style.left獲取的數值多是無效的
5、最大區別在於offsetLeft以border左上角爲基準,style.left以margin左上角爲基準
\----------------------------------------------------------------------------------------------
@scrollHeight和scrollWidth
標籤內部實際內容的高度/寬度
不計算邊框,若是內容不超出盒子,值爲盒子的寬高(不帶邊框)
若是內容超出了盒子,就是從頂部或左部邊框內側一直到內容a的最外部分
\----------------------------------------------------------------------------------------------
@scrollTop和scrollLeft
被捲去部分的 頂部/左側 到可視區域 頂部/左側 的距離
複製代碼

如何解決不一樣瀏覽器的樣式兼容性問題?

  • 在肯定問題緣由和有問題的瀏覽器後,使用單獨的樣式表,僅供出現問題的瀏覽器加載。這種方法須要使用服務器端渲染。

  • 使用已經處理好此類問題的庫,好比 Bootstrap。

  • 使用 autoprefixer 自動生成 CSS 屬性前綴。

  • 使用 Reset CSS 或 Normalize.css。

如何爲功能受限的瀏覽器提供頁面? 使用什麼樣的技術和流程?

  • 優雅的降級:爲現代瀏覽器構建應用,同時確保它在舊版瀏覽器中正常運行。

  • 漸進式加強:構建基於用戶體驗的應用,但在瀏覽器支持時添加新增功能。

  • 利用 caniuse.com 檢查特性支持。

  • 使用 autoprefixer 自動生成 CSS 屬性前綴。

  • 使用 Modernizr進行特性檢測。

{box-sizing: border-box;}會產生怎樣的效果?

  • 元素默認應用了box-sizing: content-box,元素的寬高只會決定內容(content)的大小。

  • box-sizing: border-box改變計算元素widthheight的方式,borderpadding的大小也將計算在內。

  • 元素的height = 內容(content)的高度 + 垂直方向的padding + 垂直方向border的寬度

  • 元素的width = 內容(content)的寬度 + 水平方向的padding + 水平方向border的寬度

文本超出部分顯示省略號

  • 單行
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
複製代碼
  • 多行
display: -webkit-box;
-webkit-box-orient: vertical;
/* 最多顯示幾行*/
-webkit-line-clamp: 3; 
overflow: hidden;
複製代碼

JavaScript

訂閱發佈

觀察者

cmd commonjs amd

列舉 3 種強制類型轉換和 2 種隱式類型轉換

  • 強制(parseInt,parseFloat,Number)、隱式(+ -)

js基本數據類型、引用數據類型,null、undefined的區別

  • 基本數據類型有:String、Number、Boolean、Symbol、Null、Undefined
  • 引用類型:Object、Array、Function
  • null是空對象,undefined是未定義的值

判斷Array類型、Number類型

  • typeof
  • instanceof
  • Object.prototype.toString.call()
  • Array.isArray

Object是引用類型嗎?引用類型和基本類型的區別?哪一個在堆哪一個在棧

  • Object是引用類型
  • 引用類型是按引用範文,基本類型是按值訪問。
  • 引用類型在棧裏保存一個十六進制的空間地址,指向堆內存中的一個對象,基本數據類型存儲在棧中

DOM操做Api

  • Document.getElementById, ByTagName、ByClassName\querySelector\querySelectAll
  • createElement\ createTextNode\ cloneNode\ createDocumentFragment
  • appendChild\insertChild\removeChild\replaceChild
  • setAttribute\getAttribute\dataset

this的使用場景

  • 函數有所屬對象指向所屬對象,沒有則指向全局對象
  • new 一個對象時指向這個對象
  • call\apply\bind 改變this的指向

建立對象的方式

  • 工廠模式
function Person(name) {
	var o = new Object;
  o.age = name;
  o.sayName = function(){
    console.log(this.name);
  }
  return o;
}
// 缺點:對象沒法識別
複製代碼
  • 構造函數模式
function person(name) {
  this.name = name;
  // 優化點:能夠把函數放到外面,這樣每次建立實例的時候函數就不會被從新建立
  this.sayName = function() {
    console.log(this.name)
  }
}
// 優勢:能夠識別對象的類型
// 缺點:每次建立實例函數都要從新建立一遍
複製代碼
  • 原型模式
function Person() {}
person.prototype.name = 'nick';
person.prototype.sayName = function(){
  console.log(this.name);
}
var person1 = new Person();
// 優勢:方法和屬性都共享
// 缺點:不能初始化參數

// 優化版
function Person(name) {}
Person.prototype = {
    constructor: Person,
    name: 'nick',
    getName: function () {
        console.log(this.name);
    }
};

var person1 = new Person();
// 能夠經過constructor找到所屬構造函數
複製代碼
  • 組合模式
function Person(name) {
  this.name = name;
}
person.prototype = function() {
  console.log(this.name);
}
const person = new Person('nick');
// 優勢:方法共享,變量私有。
複製代碼
  • 動態原型模式
function Person(name) {
  this.name = name;
    if (typeof this.sayName != 'function') {
    	Person.prototype.sayName = function() {
    	console.log(this.name);
    }
  }
}
複製代碼
  • 寄生構造函數模式
function Person(name) {
	var o = new Object;
  o.age = name;
  o.sayName = function(){
    console.log(this.name);
  }
  return o;
}

// 示例
function SpecialArray() {
    var values = new Array();
    for (var i = 0, len = arguments.length; i < len; i++) {
        values.push(arguments[i]);
    }
    values.toPipedString = function () {
        return this.join("|");
    };
    return values;
}

var colors = new SpecialArray('red', 'blue', 'green');
var colors2 = SpecialArray('red2', 'blue2', 'green2');

console.log(colors);
console.log(colors.toPipedString()); // red|blue|green

console.log(colors2);
console.log(colors2.toPipedString()); // red2|blue2|green2
// 你會發現,其實所謂的寄生構造函數模式就是比工廠模式在建立對象的時候,多使用了一個new,實際上二者的結果是同樣的。
複製代碼
  • 穩妥構造函數模式
function Person(name) {
	var o = new Object;
  o.sayName = function(){
    console.log(this.name);
  }
  return o;
}
// 沒有公共屬性
複製代碼

new 操做符

  • 一、建立一個空的新對象,(如:var car1 = {});
  • 二、新對象的__proto__屬性指向構造函數的原型對象。(原型.prototype)
  • 三、將構造函數的做用域賦值給新對象。(即this指向這個新對象)
  • 四、執行構造函數內部的代碼,爲這個新對象添加屬性。
  • 五、若是該函數沒有返回對象,則隱式的返回this。
// 定義構造函數
function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}

var car1 = new Car('Eagle', 'Talon TSi', 1993);
console.log(car1.make);
// expected output: "Eagle"
複製代碼

什麼是「use strict」, 好處和壞處

變量必須先聲明,再使用
不能對變量執行delete操做
對象的屬性名不能重複
禁用eval()
函數的arguments參數
禁用with(){}
複製代碼

變量提高

  • 在當前做用域下,代碼運行以前,把帶var的和帶function進行提早聲明,
  • 帶var的只聲明,不定義(不賦值),帶function聲明加定義。
  • 函數定義三步:
    • 開闢一個堆內存,會有一個十六進制的空間地址(指正)
    • 把函數體中的代碼當作字符串存儲進行
    • 把空間地址(指針)賦值給函數名;
  • 特殊狀況
    • 無論條件是否成立,都要進行變量提高
      • function在新的瀏覽器中只聲明不定義,舊瀏覽器聲明加定義
    • 變量提高只發生在等號左邊
    • return以後代碼不執行,但要進行變量提高
    • 變量名重複,不須要重複聲明但要從新定義
    • 匿名函數不進行變量提高

做用域

  • 全局做用域:在代碼中任何地方都能訪問到的對象擁有全局做用域。
    • 擁有全局做用域的有 window對象的屬性 定義在最外層的函數或變量 未定義直接賦值的變量
  • 局部做用域:通常在代碼片斷內能夠訪問到的,最多見的如函數內部,因此又稱函數做用域
  • 塊級做用域: 在任何一對{}中的定義的變量在代碼塊外都不可見。

堆棧內存

  • 棧是一種遵循先進後出原則的有序集合,主要用來提供JavaScript的運行環境和存儲基本數據類型值
  • 堆的數據結構是一種樹狀結構,特色是存儲的鍵值對(key-value)能夠是無序的,主要用來存儲引用數據類型值
  • 棧內存釋放
    • 通常狀況下,當函數執行完所造成的私有做用域會被自動釋放掉,但也有特殊不銷燬的狀況
      • 函數內的某些內容被外部變量佔用了。(閉包)
      • 全局棧內存只有在頁面關閉的時候纔會被釋放
  • 堆內存釋放
    • 讓引用堆內存空間地址的變量賦值爲null.
const ary = [1,2,3,4,5,6];
Math.max(1,2,3,4,5,6);
Math.max.call()

1 === '1'
1== '1'

[1] == [2]

複製代碼

閉包的理解?

  • 三個特性
    • 函數嵌套函數
    • 內部函數能夠訪問外部函數的參數和變量
    • 參數和變量不會被垃圾機制回收
  • 優勢
    • 變量長期保存在內存中
    • 避免全局變量污染
  • 缺點
    • 常駐內存,增長內存使用量
    • 使用不當會形成內存泄漏

實現跨域有多少種方式

jsonp

  • Jsonp原理利用script標籤沒有跨域限制的漏洞,從其餘來源動態獲取數據,jsonp請求須要服務器支持才能夠,jsonp屬於非同源
  • jsonp的優勢是簡單、兼容性好,缺點是隻支持get請求,但可能會遭受xss攻擊
  • jsonp實現的方式是經過將前端方法以參數的形式傳遞給服務端,服務端注入參數再返回,實現服務端向客戶端通訊

cors跨資源共享

  • CORS是一個W3C標準,全稱是跨域資源共享,容許瀏覽器向跨域服務器發送XMLHttpRequest/Fetch請求。
  • 實現通訊的關鍵是服務器,只要服務器實現了CORS接口,就能夠跨域通訊。
res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("Content-Type", "application/json;charset=utf-8");
複製代碼

node中間件代理/webpack的devServer代理

  • 接受客戶端請求 => 將請求轉發給服務器 => 拿到服務器的響應數據 => 將響應數據轉發給客戶端

nginx反向代理

  • 和Node代理同樣的原理,只須要修改nginx的配置項

websocket

  • Websocket是一種雙向通訊協議,創建鏈接以後,server端和client端都能主動向對方接收/發送數據。

postMessage

  • 主要解決頁面和新窗口的數據傳遞,多窗口的數據傳遞,頁面和嵌套的iframe消息傳遞

window.name + iframe,localtion.hash + iframe,document.domain + iframe

瞭解過,沒用過。

淺拷貝和深拷貝區別

  • 淺拷貝

    • 淺拷貝會建立了一個新對象,這個對象有原始對象屬性值的一份精確拷貝。屬性值若是是基本類型則拷貝變量的值,引用類型則拷貝內存地址,若是其中一個對象改變了則會影響另外一個對象。
    • 常使用方法
    • Object.assign():將全部可枚舉的值從一個或多個源對象複製到目標對象
    • ES6的展開運算符
    • Array.prototype.slice()返回數組的淺拷貝
  • 深拷貝

    • 深拷貝會拷貝基本類型的值並拷貝引用類型指向的對象。深拷貝相對於淺拷貝速度較慢而且花銷較大,但拷貝後兩個對象互補不影響
    • 能夠用JSON.parse(JSON.stringify(object))進行深拷貝,但會有幾個問題,好比不能處理正則,不能處理new Date,不能序列化函數,會忽略undefinedsymbol
  • 總結:

    • 若是基本數據,淺拷貝和深拷貝都不會改變原數據
    • 若是是引用類型,淺拷貝的對象改變會影響原對象,深拷貝則不會。
  • 實現一個深拷貝

// 簡單深拷貝
const cloneDeep = (source) => {
  let target = Array.isArray(source) ? [] : {};
  for(const key in source) {
    const val = source[key];
    if(typeof val === 'object') {
      target[key] = cloneDeep(val);
    } else {
      target[key] = val;
    }
  }
  return target;
}


// 加強版的深拷貝
const isObject = (object) => {
    // 兼容數組
    return typeof object === 'object' && object != null;
}

const cloneDeep = (source) => {
    // 參數校驗
    if(!isObject(source)) return source;

    let target = Array.isArray(source) ? [] : {};
    // 哈希表解決循環引用
    let hash = new WeakMap();
    hash.set(source, target);

    for (const key in source) {
        // hasOwnProperty: 檢測對象自身屬性中是否具備指定的屬性,返回布爾值
        if (source.hasOwnProperty(key)) {
            if(typeof source[key] === 'object') {
                // 遞歸實現深拷貝
                target[key] = cloneDeep(source[key]);
            } else {
                target[key] = source[key];
            }
        }
    }
    return target;
}

var a = {
    name: "muyiy",
    book: {
        title: "You Don't Know JS",
        price: "45",
        demo: {
            demo: {
                demo: {}
            },
            demo1: {
                demo: {}
            },
            demo2: {
                demo: {}
            }
        }
    },
    a1: undefined,
    a2: null,
    a3: 123
}

var b = cloneDeep(a);
a.name = "高級前端進階";
a.book.price = "55";
a.circleRef = a;
b.book.demo.demo.demo.a = 2;
console.log(a);
console.log(b);
複製代碼

原型鏈、手繪原型鏈

原型

  • 函數都帶有一個prototype屬性,這是屬性是指向構造函數原型對象,這個對象包含全部實例共享的屬性和方法。
  • 原型對象都有一個constructor屬性,這個屬性指向所關聯的構造函數。
  • 每一個對象都有一個__proto__屬性[非標準的方法],這個屬性指向構造函數的原型prototype

原型鏈

  • 當訪問實例對象的某個屬性時,會先在這個對象自己的屬性上查找,若是沒有找到,則會經過__proto__屬性去原型上查找,若是尚未找到則會在構造函數的原型的__proto__中查找,這樣一層層向上查找就會造成一個做用域鏈,稱爲原型鏈

爲何要有原型鏈

  • 構造函數的全部實例均可以訪問構造函數原型上的屬性和方法
  • 繼承,子類能夠繼承父類的方法

手繪原型圖

![image-20191015085835130](/Users/zenghp/Library/Application Support/typora-user-images/image-20191015085835130.png)

事件冒泡/事件捕獲/事件委託(事件代理)

  • 事件冒泡
    • 由裏向外傳播,直到document對象
  • 事件捕獲
    • 由外向裏傳播直到最具體的元素.
  • 事件委託/事件代理
    • 事件委託/代理就是利用事件冒泡,只指定一個事件處理器就能夠管理某一類型的全部事件。
    • 優勢:
      • 減小大量的內存佔用,事件註冊。
      • 動態新增元素無需再對其綁定事件
    • 缺點:
      • 若是全部事件都用委託/代理的話會出現本不該該綁定的事件被綁上了事件
  • 阻止冒泡
event.stopPropagation()
//非標準,已廢棄
event.cancelBubble=false; // IE
複製代碼
  • 阻止事件的默認行爲
event.preventDefault()
//非標準,已廢棄
event.returnValue=false; //IE
複製代碼

手寫Ajax

  • promise Ajax
let getJson = url => {
    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest();
        xhr.open('get', url);
        xhr.onreadystatechange = () => {
            if (xhr.readyState !== 4) return;

            if (xhr.readyState === 4 && 200 === xhr.status) {
                resolve(xhr.responseText);
            } else {
                reject();
            }
        };
        xhr.send();
    });
};

getJson('/login').then(function (res) {
    return getJson('/order');
}).then(function(res){
    console.log(res);
}).catch(function (err) {
    console.log('error')
})
複製代碼
  • 普通函數
let xhr = new XMLHttpRequest();
xhr.open('get', 'http://xxx.com');
xhr.onreadystatechange = () => {
  if (xhr.readyState !== 4) return;
  if (200 === xhr.status) {
    console.log(xhr.responseText)
  }
};
xhr.send();
複製代碼

防抖、節流

防抖(debounce)

指的是某個函數在某段時間內,不管觸發了多少次回調,都只執行最後一次。

  • 實現方案 使用定時器,函數第一次執行時設定一個定時器,以後調用時發現已經設定過定時器就清空以前的定時器,並從新設定一個新的定時器,若是存在沒有被清空的定時器,當定時器計時結束後觸發函數執行

  • 示例

/** * 延遲執行 * fn: 須要防抖的函數 * wait: 時間間隔 * */
function debounce(fn, wait = 50) {
    let timer = null;
    return function(...args) {
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(this, args);
        }, wait)
    }
}

/** * 當即執行 * fn: 須要防抖的函數 * wait: 時間間隔 * */
function debounce(fn, wait = 50) {
    let timer = null;
    return function(...args) {
        if (timer) clearTimeout(timer);
        let callNow = !timer;
        timer = setTimeout(() => {
            timer = null;
        }, wait);
        if (callNow) fn.apply(this, args);
    }
}
複製代碼

節流(throttle)

函數節流指的是某個函數在必定時間間隔內只執行一次,在這間隔內無視後來產生的函數調用請求

  • 實現方案

    • 每次執行時設定一個上次執行的時間戳,判斷是否已到執行時間,若是到了就執行。

    • 設定一個定時器,若是定時器存在則直接返回,等待異步執行完畢清空定時器。

  • 示例

// 時間戳
const throttle = (fn, wait = 50) => {
  // 上一次執行 fn 的時間
  let previous = 0;
  // 將 throttle 處理結果看成函數返回
  return function(...args) {
    // 獲取當前時間,轉換成時間戳,單位毫秒
    let now = +new Date();
    // 將當前時間和上一次執行函數的時間進行對比
    // 大於等待時間就把 previous 設置爲當前時間並執行函數 fn
    if (now - previous > wait) {
      previous = now
      fn.apply(this, args)
    }
  }
}

// 定時器版本
const throttle = function(fn, wait) {
    let timer = null;
    return function(...args) {
        if (timer) return;
        timer = setTimeout(() => {
            timer = null;
            fn.apply(this, args);
        }, wait);
    };
}
複製代碼

數組去重

const ary1 = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
const ary2 = ary1.filter((element, index, ary) => {
  // 判斷索引是否相等
  return ary.indexOf(element) === index;
}) // => [1, 2, 3, 5, 4]

const ary3 = [...new Set(arr1)]
// => [1, 2, 3, 5, 4]

const ary4 = Array.from(new Set(arr1))
// => [1, 2, 3, 5, 4]

const ary5 = arr1.reduce((prev, next) => {
    return prev.includes(next) ? prev : [...prev, next];
}, []);
複製代碼

new 一個對象具體作了什麼

  • 一、建立一個空的新對象,(如:var car1 = {});
  • 二、新對象的_proto_屬性指向構造函數的原型對象。(原型.prototype)
  • 三、將構造函數的做用域賦值給新對象。(即this指向這個新對象)
  • 四、執行構造函數內部的代碼,爲這個新對象添加屬性。
  • 五、若是該函數沒有返回對象,則隱式的返回this。
// 定義構造函數
function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}

var car1 = new Car('Eagle', 'Talon TSi', 1993);
console.log(car1.make);
// expected output: "Eagle"
複製代碼

call\apply\bind

  • call:使用一個指定的 this 值和單獨給出的一個或多個參數來調用一個函數。

fun.call(thisArg[,arg1[,arg2[, ...]]])

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}

console.log(new Food('cheese', 5).name); //=>"cheese"
複製代碼
  • apply: 調用一個具備給定this值的函數,以及做爲一個數組(或相似數組對象)提供的參數

fun.apply(thisArg, argsArray)

var numbers = [5, 6, 2, 3, 7];
// 最大值
var max = Math.max.apply(null, numbers);
console.log(max); //=> 7
// 最小值
var min = Math.min.apply(null, numbers);
console.log(min); //=> 2
複製代碼
  • bind:建立一個新的函數,在bind被調用時,這個新函數的this被bind的第一個參數指定,其他的參數將做爲新函數的參數供調用時使用。

function.bind(thisArg[,arg1[,arg2[, ...]]])

var module = {
  x: 42,
  getX: function() {
    return this.x;
  }
}

var unboundGetX = module.getX;
console.log(unboundGetX()); // => undefined

var boundGetX = unboundGetX.bind(module);
console.log(boundGetX()); // => 42
複製代碼

數組API

Array.from()

  • 從一個相似數組或可迭代對象中建立一個新的,淺拷貝的數組實例。
console.log(Array.from('foo'));
// expected output: Array ["f", "o", "o"]

console.log(Array.from([1, 2, 3], x => x + x));
// expected output: Array [2, 4, 6]
複製代碼

Array.isArray()

  • 用於肯定傳遞的值是不是一個 Array。
Array.isArray([1, 2, 3]);  
// true
Array.isArray({foo: 123}); 
// false
Array.isArray("foobar");   
// false
Array.isArray(undefined);  
// false
複製代碼

Array.prototype.concat()

  • 合併兩個或多個數組。此方法不會更改現有數組,返回新數組。
const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
console.log(array1.concat(array2));
// expected output: Array ["a", "b", "c", "d", "e", "f"]
複製代碼

Array.prototype.every()

  • 測試一個數組內的全部元素是否都能經過某個指定函數的測試。返回布爾值。
var array1 = [1, 30, 39, 29, 10, 13];
function isBelowThreshold(currentValue) {
  return currentValue < 40;
}
console.log(array1.every(isBelowThreshold));
// expected output: true
複製代碼

Array.prototype.filter()

  • 建立一個新數組, 其包含經過所提供函數實現的測試的全部元素。
var words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]
複製代碼

Array.prototype.some()

  • 測試數組中是否是有元素經過了被提供的函數測試。它返回的是一個Boolean類型的值。
var array = [1, 2, 3, 4, 5];

var even = function(element) {
  // checks whether an element is even
  return element % 2 === 0;
};

console.log(array.some(even));
// expected output: true
複製代碼

Array.prototype.find()

  • 返回數組中知足提供的測試函數的第一個元素的值。不然返回undefined
var array1 = [5, 12, 8, 130, 44];
var found = array1.find(function(element) {
  return element > 10;
});
console.log(found);
// expected output: 12
複製代碼

Array.prototype.findIndex()

  • 返回數組中知足提供的測試函數的第一個元素的索引。不然返回-1。
var array1 = [5, 12, 8, 130, 44];
function isLargeNumber(element) {
  return element > 13;
}
console.log(array1.findIndex(isLargeNumber));
// expected output: 3
複製代碼

Array.prototype.forEach()

  • 對數組的每一個元素執行一次提供的函數。
var array1 = ['a', 'b', 'c'];

array1.forEach(function(element) {
  console.log(element);
});

// expected output: "a"
// expected output: "b"
// expected output: "c"
複製代碼

Array.prototype.map()

  • 建立一個新數組,其結果是該數組中的每一個元素都調用一個提供的函數後返回的結果。
var array1 = [1, 4, 9, 16];
// pass a function to map
const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: Array [2, 8, 18, 32]
複製代碼

Array.prototype.includes()

  • 用來判斷一個數組是否包含一個指定的值,根據狀況,若是包含則返回 true,不然返回false。
var array1 = [1, 2, 3];

console.log(array1.includes(2));
// expected output: true

var pets = ['cat', 'dog', 'bat'];

console.log(pets.includes('cat'));
// expected output: true

console.log(pets.includes('at'));
// expected output: false
複製代碼

Array.prototype.indexOf()

  • 返回在數組中能夠找到一個給定元素的第一個索引,若是不存在,則返回-1。
var beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];

console.log(beasts.indexOf('bison'));
// expected output: 1

// start from index 2
console.log(beasts.indexOf('bison', 2));
// expected output: 4

console.log(beasts.indexOf('giraffe'));
// expected output: -1
複製代碼

Array.prototype.lastIndexOf()

  • 返回指定元素(也即有效的 JavaScript 值或變量)在數組中的最後一個的索引,若是不存在則返回 -1。從數組的後面向前查找,從 fromIndex 處開始。
var animals = ['Dodo', 'Tiger', 'Penguin', 'Dodo'];

console.log(animals.lastIndexOf('Dodo'));
// expected output: 3

console.log(animals.lastIndexOf('Tiger'));
// expected output: 1
複製代碼

Array.prototype.join()

  • 將一個數組(或一個類數組對象)的全部元素鏈接成一個字符串並返回這個字符串。若是數組只有一個項目,那麼將返回該項目而不使用分隔符。
var elements = ['Fire', 'Air', 'Water'];

console.log(elements.join());
// expected output: "Fire,Air,Water"

console.log(elements.join(''));
// expected output: "FireAirWater"

console.log(elements.join('-'));
// expected output: "Fire-Air-Water"
複製代碼

Array.prototype.flat()

  • 按照一個可指定的深度遞歸遍歷數組,並將全部元素與遍歷到的子數組中的元素合併爲一個新數組返回。
var arr1 = [1, 2, [3, 4]];
arr1.flat(); 
// [1, 2, 3, 4]

var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]

var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]

//使用 Infinity 做爲深度,展開任意深度的嵌套數組
arr3.flat(Infinity); 
// [1, 2, 3, 4, 5, 6]

var arr4 = [1, 2, , 4, 5];
arr4.flat();
// [1, 2, 4, 5]
複製代碼

Array.prototype.flatMap()

var arr1 = [1, 2, 3, 4];

arr1.map(x => [x * 2]); 
// [[2], [4], [6], [8]]

arr1.flatMap(x => [x * 2]);
// [2, 4, 6, 8]

// 只會將 flatMap 中的函數返回的數組 「壓平」 一層
arr1.flatMap(x => [[x * 2]]);
// [[2], [4], [6], [8]]

let arr = ["今每天氣不錯", "", "早上好"]

arr.map(s => s.split(""))
// [["今", "天", "天", "氣", "不", "錯"],[],["早", "上", "好"]]

arr.flatMap(s => s.split(''));
// ["今", "天", "天", "氣", "不", "錯", "早", "上", "好"]
複製代碼

Array.prototype.keys()

  • 返回一個包含數組中每一個索引鍵的Array Iterator對象。
var array1 = ['a', 'b', 'c'];
var iterator = array1.keys(); 
  
for (let key of iterator) {
  console.log(key); // expected output: 0 1 2
}
複製代碼

Array.prototype.values()

  • 返回一個新的Array Iterator對象,該對象包含數組每一個索引的值
const array1 = ['a', 'b', 'c'];
const iterator = array1.values();

for (const value of iterator) {
  console.log(value); // expected output: "a" "b" "c"
}
複製代碼

Array.prototype.pop()

  • 從數組中刪除最後一個元素,並返回該元素的值。此方法更改數組的長度。
var plants = ['broccoli', 'cauliflower', 'cabbage', 'kale', 'tomato'];

console.log(plants.pop());
// expected output: "tomato"

console.log(plants);
// expected output: Array ["broccoli", "cauliflower", "cabbage", "kale"]

plants.pop();

console.log(plants);
// expected output: Array ["broccoli", "cauliflower", "cabbage"]
複製代碼

Array.prototype.push()

  • 將一個或多個元素添加到數組的末尾,並返回該數組的新長度。
const animals = ['pigs', 'goats', 'sheep'];

const count = animals.push('cows');
console.log(count);
// expected output: 4
console.log(animals);
// expected output: Array ["pigs", "goats", "sheep", "cows"]

animals.push('chickens', 'cats', 'dogs');
console.log(animals);
// expected output: Array ["pigs", "goats", "sheep", "cows", "chickens", "cats", "dogs"]
複製代碼

Array.prototype.shift()

  • 從數組中刪除第一個元素,並返回該元素的值。此方法更改數組的長度。
var array1 = [1, 2, 3];

var firstElement = array1.shift();

console.log(array1);
// expected output: Array [2, 3]

console.log(firstElement);
// expected output: 1
複製代碼

Array.prototype.unshift()

  • 將一個或多個元素添加到數組的開頭,並返回該數組的新長度(該方法修改原有數組)。
var array1 = [1, 2, 3];

console.log(array1.unshift(4, 5));
// expected output: 5

console.log(array1);
// expected output: Array [4, 5, 1, 2, 3]

複製代碼

Array.prototype.reduce()

  • 對數組中的每一個元素執行一個由您提供的reducer函數(升序執行),將其結果彙總爲單個返回值。
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10

// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15
複製代碼

Array.prototype.reduceRight()

  • 接受一個函數做爲累加器(accumulator)和數組的每一個值(從右到左)將其減小爲單個值。
const array1 = [[0, 1], [2, 3], [4, 5]].reduceRight(
  (accumulator, currentValue) => accumulator.concat(currentValue)
);

console.log(array1);
// expected output: Array [4, 5, 2, 3, 0, 1]
複製代碼

Array.prototype.reverse()

  • 將數組中元素的位置顛倒,並返回該數組。該方法會改變原數組。
var array1 = ['one', 'two', 'three'];
console.log('array1: ', array1);
// expected output: Array ['one', 'two', 'three']

var reversed = array1.reverse(); 
console.log('reversed: ', reversed);
// expected output: Array ['three', 'two', 'one']

/* Careful: reverse is destructive. It also changes the original array */ 
console.log('array1: ', array1);
// expected output: Array ['three', 'two', 'one']
複製代碼

Array.prototype.slice()

  • 返回一個新的數組對象,這一對象是一個由 begin 和 end 決定的原數組的淺拷貝(包括 begin,不包括end)。原始數組不會被改變。
var animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];

console.log(animals.slice(2));
// expected output: Array ["camel", "duck", "elephant"]

console.log(animals.slice(2, 4));
// expected output: Array ["camel", "duck"]

console.log(animals.slice(1, 5));
// expected output: Array ["bison", "camel", "duck", "elephant"]
複製代碼

Array.prototype.splice()

  • 經過刪除或替換現有元素或者原地添加新的元素來修改數組,並以數組形式返回被修改的內容。此方法會改變原數組
var months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb');
// inserts at index 1
console.log(months);
// expected output: Array ['Jan', 'Feb', 'March', 'April', 'June']

months.splice(4, 1, 'May');
// replaces 1 element at index 4
console.log(months);
// expected output: Array ['Jan', 'Feb', 'March', 'April', 'May']
複製代碼

Array.prototype.sort()

  • 用原地算法對數組的元素進行排序,並返回數組。默認排序順序是在將元素轉換爲字符串,而後比較它們的UTF-16代碼單元值序列時構建的
var months = ['March', 'Jan', 'Feb', 'Dec'];
months.sort();
console.log(months);
// expected output: Array ["Dec", "Feb", "Jan", "March"]

var array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1);
// expected output: Array [1, 100000, 21, 30, 4]
複製代碼

Array.prototype.toLocaleString()

  • 返回一個字符串表示數組中的元素。數組中的元素將使用各自的 toLocaleString 方法轉成字符串,這些字符串將使用一個特定語言環境的字符串(例如一個逗號 ",")隔開。
var array1 = [1, 'a', new Date('21 Dec 1997 14:12:00 UTC')];
var localeString = array1.toLocaleString('en', {timeZone: "UTC"});

console.log(localeString);
// expected output: "1,a,12/21/1997, 2:12:00 PM",
// This assumes "en" locale and UTC timezone - your results may vary
複製代碼

Array.prototype.toString()

  • 返回一個字符串,表示指定的數組及其元素。
var array1 = [1, 2, 'a', '1a'];

console.log(array1.toString());
// expected output: "1,2,a,1a"
複製代碼

字符串API

String.fromCharCode()

  • String.fromCharCode(num1, ..., numN)
  • 返回由指定的UTF-16代碼單元序列建立的字符串。
console.log(String.fromCharCode(189, 43, 190, 61));
// expected output: "½+¾="
複製代碼

String.fromCodePoint()

  • 返回使用指定的代碼點序列建立的字符串。
console.log(String.fromCodePoint(9731, 9733, 9842, 0x2F804));
// expected output: "☃★♲你"
複製代碼

String.prototype.charAt()

  • 從一個字符串中返回指定的字符。
var anyString = "Brave new world";
console.log("The character at index 0 is '" + anyString.charAt(0)   + "'");
console.log("The character at index 1 is '" + anyString.charAt(1)   + "'");
console.log("The character at index 2 is '" + anyString.charAt(2)   + "'");
console.log("The character at index 3 is '" + anyString.charAt(3)   + "'");
console.log("The character at index 4 is '" + anyString.charAt(4)   + "'");
console.log("The character at index 999 is '" + anyString.charAt(999) + "'");
複製代碼

String.prototype.charCodeAt()

  • 返回0到65535之間的整數,表示給定索引處的UTF-16代碼單元 (在 Unicode 編碼單元表示一個單一的 UTF-16 編碼單元的狀況下,UTF-16 編碼單元匹配 Unicode 編碼單元。但在——例如 Unicode 編碼單元 > 0x10000 的這種——不能被一個 UTF-16 編碼單元單獨表示的狀況下,只能匹配 Unicode 代理對的第一個編碼單元) 。若是你想要整個代碼點的值,使用 codePointAt()。
var sentence = 'The quick brown fox jumps over the lazy dog.';
var index = 4;

console.log('The character code ' + sentence.charCodeAt(index) + ' is equal to ' + sentence.charAt(index));
// expected output: "The character code 113 is equal to q"
複製代碼

String.prototype.codePointAt()

  • 返回 一個 Unicode 編碼點值的非負整數。
'ABC'.codePointAt(1);          // 66
'\uD800\uDC00'.codePointAt(0); // 65536
'XYZ'.codePointAt(42); // undefined
複製代碼

String.prototype.concat()

  • 將一個或多個字符串與原字符串鏈接合併,造成一個新的字符串並返回。
var hello = "Hello, ";
console.log(hello.concat("Kevin", " have a nice day.")); /* Hello, Kevin have a nice day. */
複製代碼

String.prototype.startsWith()

  • 用來判斷當前字符串是否以另一個給定的子字符串開頭,並根據判斷結果返回 true 或 false。
const str1 = 'Saturday night plans';

console.log(str1.startsWith('Sat'));
// expected output: true

console.log(str1.startsWith('Sat', 3));
// expected output: false

複製代碼

String.prototype.endsWith()

  • 用來判斷當前字符串是不是以另一個給定的子字符串「結尾」的,根據判斷結果返回 true 或 false。
const str1 = 'Cats are the best!';
console.log(str1.endsWith('best', 17));
// expected output: true
const str2 = 'Is this a question';
console.log(str2.endsWith('?'));
// expected output: false
複製代碼

String.prototype.includes()

  • 用於判斷一個字符串是否包含在另外一個字符串中,根據狀況返回 true 或 false。
var str = 'To be, or not to be, that is the question.';

console.log(str.includes('To be'));       // true
console.log(str.includes('question'));    // true
console.log(str.includes('nonexistent')); // false
console.log(str.includes('To be', 1));    // false
console.log(str.includes('TO BE'));       // false
複製代碼

String.prototype.indexOf()

  • 返回調用它的 String 對象中第一次出現的指定值的索引,從 fromIndex 處進行搜索。若是未找到該值,則返回 -1。
var paragraph = 'The quick brown fox jumps over the lazy dog. If the dog barked, was it really lazy?';
var searchTerm = 'dog';
var indexOfFirst = paragraph.indexOf(searchTerm);

console.log('The index of the first "' + searchTerm + '" from the beginning is ' + indexOfFirst);
// expected output: "The index of the first "dog" from the beginning is 40"
console.log('The index of the 2nd "' + searchTerm + '" is ' + paragraph.indexOf(searchTerm, (indexOfFirst + 1)));
// expected output: "The index of the 2nd "dog" is 52"
複製代碼

String.prototype.lastIndexOf()

  • 返回指定值在調用該方法的字符串中最後出現的位置,若是沒找到則返回 -1。length爲須要檢索字符串的長度,默認值爲str.length。
"canal".lastIndexOf("a")   // returns 3
"canal".lastIndexOf("a",2) // returns 1
"canal".lastIndexOf("a",0) // returns -1
"canal".lastIndexOf("x")   // returns -1

// 區分大小寫
"Blue Whale, Killer Whale".lastIndexOf("blue"); // returns -1
複製代碼

String.prototype.localeCompare()

  • 返回一個數字來指示一個參考字符串是否在排序順序前面或以後或與給定字符串相同。
// The letter "a" is before "c" yielding a negative value
'a'.localeCompare('c'); 
// -2 or -1 (or some other negative value)

// Alphabetically the word "check" comes after "against" yielding a positive value
'check'.localeCompare('against'); 
// 2 or 1 (or some other positive value)

// "a" and "a" are equivalent yielding a neutral value of zero
'a'.localeCompare('a'); 
// 0
複製代碼

String.prototype.match()

  • 檢索返回一個字符串匹配正則表達式的的結果。
var str = 'For more information, see Chapter 3.4.5.1';
var re = /see (chapter \d+(\.\d)*)/i;
var found = str.match(re);

console.log(found);

// logs [ 'see Chapter 3.4.5.1',
// 'Chapter 3.4.5.1',
// '.1',
// index: 22,
// input: 'For more information, see Chapter 3.4.5.1' ]

// 'see Chapter 3.4.5.1' 是整個匹配。
// 'Chapter 3.4.5.1' 被'(chapter \d+(\.\d)*)'捕獲。
// '.1' 是被'(\.\d)'捕獲的最後一個值。
// 'index' 屬性(22) 是整個匹配從零開始的索引。
// 'input' 屬性是被解析的原始字符串。

var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
var regexp = /[A-E]/gi;
var matches_array = str.match(regexp);

console.log(matches_array);
// ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e']
複製代碼

String.prototype.matchAll()

  • 返回一個包含全部匹配正則表達式及分組捕獲結果的迭代器。
const regexp = RegExp('foo*','g');
const str = 'table football, foosball';

while ((matches = regexp.exec(str)) !== null) {
  console.log(`Found ${matches[0]}. Next starts at ${regexp.lastIndex}.`);
  // expected output: "Found foo. Next starts at 9."
  // expected output: "Found foo. Next starts at 19."
}


//===

const regexp = RegExp('foo*','g'); 
const str = 'table football, foosball';
let matches = str.matchAll(regexp);

for (const match of matches) {
  console.log(match);
}
// Array [ "foo" ]
// Array [ "foo" ]

// matches iterator is exhausted after the for..of iteration
// Call matchAll again to create a new iterator
matches = str.matchAll(regexp);

Array.from(matches, m => m[0]);
// Array [ "foo", "foo" ]
複製代碼

String.prototype.normalize()

  • 按照指定的一種 Unicode 正規形式將當前字符串正規化.
// Initial string

// U+1E9B: LATIN SMALL LETTER LONG S WITH DOT ABOVE
// U+0323: COMBINING DOT BELOW
var str = "\u1E9B\u0323";


// Canonically-composed form (NFC)

// U+1E9B: LATIN SMALL LETTER LONG S WITH DOT ABOVE
// U+0323: COMBINING DOT BELOW
str.normalize("NFC"); // "\u1E9B\u0323"
str.normalize(); // same as above


// Canonically-decomposed form (NFD)

// U+017F: LATIN SMALL LETTER LONG S
// U+0323: COMBINING DOT BELOW
// U+0307: COMBINING DOT ABOVE
str.normalize("NFD"); // "\u017F\u0323\u0307"


// Compatibly-composed (NFKC)

// U+1E69: LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE
str.normalize("NFKC"); // "\u1E69"


// Compatibly-decomposed (NFKD)

// U+0073: LATIN SMALL LETTER S
// U+0323: COMBINING DOT BELOW
// U+0307: COMBINING DOT ABOVE
str.normalize("NFKD"); // "\u0073\u0323\u0307"
複製代碼

String.prototype.padEnd()

  • 會用一個字符串填充當前字符串(若是須要的話則重複填充),返回填充後達到指定長度的字符串。從當前字符串的末尾(右側)開始填充。
'abc'.padEnd(10);          // "abc "
'abc'.padEnd(10, "foo");   // "abcfoofoof"
'abc'.padEnd(6, "123456"); // "abc123"
'abc'.padEnd(1);           // "abc"
複製代碼

String.prototype.padStart()

  • 用另外一個字符串填充當前字符串(重複,若是須要的話),以便產生的字符串達到給定的長度。填充從當前字符串的開始(左側)應用的。
'abc'.padStart(10);         // " abc"
'abc'.padStart(10, "foo");  // "foofoofabc"
'abc'.padStart(6,"123465"); // "123abc"
'abc'.padStart(8, "0");     // "00000abc"
'abc'.padStart(1);          // "abc"
複製代碼

String.prototype.repeat()

  • 構造並返回一個新字符串,該字符串包含被鏈接在一塊兒的指定數量的字符串的副本。
"abc".repeat(-1)     // RangeError: repeat count must be positive and less than inifinity
"abc".repeat(0)      // ""
"abc".repeat(1)      // "abc"
"abc".repeat(2)      // "abcabc"
"abc".repeat(3.5)    // "abcabcabc" 參數count將會被自動轉換成整數.
"abc".repeat(1/0)    // RangeError: repeat count must be positive and less than inifinity

({toString : () => "abc", repeat : String.prototype.repeat}).repeat(2)   
//"abcabc",repeat是一個通用方法,也就是它的調用者能夠不是一個字符串對象.
複製代碼

String.prototype.replace()

  • 返回一個由替換值(replacement)替換一些或全部匹配的模式(pattern)後的新字符串。模式能夠是一個字符串或者一個正則表達式,替換值能夠是一個字符串或者一個每次匹配都要調用的回調函數。
var p = 'The quick brown fox jumps over the lazy dog. If the dog reacted, was it really lazy?';
var regex = /dog/gi;

console.log(p.replace(regex, 'ferret'));
// expected output: "The quick brown fox jumps over the lazy ferret. If the ferret reacted, was it really lazy?"

console.log(p.replace('dog', 'monkey'));
// expected output: "The quick brown fox jumps over the lazy monkey. If the dog reacted, was it really lazy?"
複製代碼

String.prototype.search()

  • 執行正則表達式和 String 對象之間的一個搜索匹配。
var paragraph = 'The quick brown fox jumps over the lazy dog. If the dog barked, was it really lazy?';
// any character that is not a word character or whitespace
var regex = /[^\w\s]/g;

console.log(paragraph.search(regex));
// expected output: 43

console.log(paragraph[paragraph.search(regex)]);
// expected output: "."
複製代碼

String.prototype.slice()

  • 提取某個字符串的一部分,並返回一個新的字符串,且不會改動原字符串。
var str = 'The quick brown fox jumps over the lazy dog.';

console.log(str.slice(31));
// expected output: "the lazy dog."

console.log(str.slice(4, 19));
// expected output: "quick brown fox"

console.log(str.slice(-4));
// expected output: "dog."

console.log(str.slice(-9, -5));
// expected output: "lazy"
複製代碼

String.prototype.split()

  • 使用指定的分隔符字符串將一個String對象分割成字符串數組,以將字符串分隔爲子字符串,以肯定每一個拆分的位置。
var str = 'The quick brown fox jumps over the lazy dog.';

var words = str.split(' ');
console.log(words[3]);
// expected output: "fox"

var chars = str.split('');
console.log(chars[8]);
// expected output: "k"

var strCopy = str.split();
console.log(strCopy);
// expected output: Array ["The quick brown fox jumps over the lazy dog."]
複製代碼

String.prototype.substring()

  • 返回一個字符串在開始索引到結束索引之間的一個子集, 或從開始索引直到字符串的末尾的一個子集。
var anyString = "Mozilla";

// 輸出 "Moz"
console.log(anyString.substring(0,3));
console.log(anyString.substring(3,0));
console.log(anyString.substring(3,-3));
console.log(anyString.substring(3,NaN));
console.log(anyString.substring(-2,3));
console.log(anyString.substring(NaN,3));

// 輸出 "lla"
console.log(anyString.substring(4,7));
console.log(anyString.substring(7,4));

// 輸出 ""
console.log(anyString.substring(4,4));

// 輸出 "Mozill"
console.log(anyString.substring(0,6));

// 輸出 "Mozilla"
console.log(anyString.substring(0,7));
console.log(anyString.substring(0,10));
複製代碼

String.prototype.toLocaleLowerCase()

  • 根據任何特定於語言環境的案例映射,返回調用字符串值轉換爲小寫的值
console.log('ALPHABET'.toLocaleLowerCase()); 
// 'alphabet'

console.log('中文簡體 zh-CN || zh-Hans'.toLocaleLowerCase());
// '中文簡體 zh-cn || zh-hans'
複製代碼

String.prototype.toLocaleUpperCase()

  • 本地化(locale-specific)的大小寫映射規則將輸入的字符串轉化成大寫形式並返回結果字符串。
console.log('alphabet'.toLocaleUpperCase()); // 'ALPHABET'
複製代碼

String.prototype.toLowerCase()

  • 將調用該方法的字符串值轉爲小寫形式,並返回。
console.log('中文簡體 zh-CN || zh-Hans'.toLowerCase());
// 中文簡體 zh-cn || zh-hansconsole.log( "ALPHABET".toLowerCase() ); 
// "alphabet"
複製代碼

String.prototype.toUpperCase()

  • 調用該方法的字符串值轉換爲大寫形式,並返回。
console.log( "alphabet".toUpperCase() ); // "ALPHABET"
複製代碼

String.prototype.toString()

  • 返回指定對象的字符串形式。
var x = new String("Hello world");
alert(x.toString())      // 輸出 "Hello world"
複製代碼

String.prototype.trim()

  • 會從一個字符串的兩端刪除空白字符。在這個上下文中的空白字符是全部的空白字符 (space, tab, no-break space 等) 以及全部行終止符字符(如 LF,CR)。
var orig = ' foo ';
console.log(orig.trim()); // 'foo'

// 另外一個.trim()例子,只從一邊刪除

var orig = 'foo ';
console.log(orig.trim()); // 'foo'
複製代碼

String.prototype.trimRight()/trimEnd()

  • 從一個字符串的右端移除空白字符。trimRight()trimEnd()方法的別名。
var greeting = ' Hello world! ';

console.log(greeting);
// expected output: " Hello world! ";

console.log(greeting.trimEnd());
console.log(greeting.trimRight());
// expected output: " Hello world!";
複製代碼

String.prototype.trimLeft()/trimStart()

  • 從字符串的開頭刪除空格。trimLeft()是trimStart()方法的別名。
var str = " foo ";

alert(str.length); // 8

str = str.trimLeft();
alert(str.length); // 5
document.write( str );
複製代碼

String.prototype.valueOf()

  • 返回一個String對象的原始值(primitive value)。
x = new String("Hello world");
alert(x.valueOf())          // Displays "Hello world"
複製代碼

String.raw()

  • 是一個模板字符串的標籤函數,它的做用相似於 Python 中的字符串前綴 r 和 C# 中的字符串前綴 @(仍是有點區別的,詳見隔壁 Chromium 那邊的這個 issue),是用來獲取一個模板字符串的原始字符串的,好比說,佔位符(例如 ${foo})會被處理爲它所表明的其餘字符串,而轉義字符(例如 \n)不會。
String.raw`Hi\n${2+3}!`;
// 'Hi\n5!',Hi 後面的字符不是換行符,\ 和 n 是兩個不一樣的字符

String.raw `Hi\u000A!`;             
// "Hi\\u000A!",同上,這裏獲得的會是 \、u、0、0、0、A 6個字符,
// 任何類型的轉義形式都會失效,保留原樣輸出,不信你試試.length

let name = "Bob";
String.raw `Hi\n${name}!`;             
// "Hi\nBob!",內插表達式還能夠正常運行


// 正常狀況下,你也許不須要將 String.raw() 看成函數調用。
// 可是爲了模擬 `t${0}e${1}s${2}t` 你能夠這樣作:
String.raw({ raw: 'test' }, 0, 1, 2); // 't0e1s2t'
// 注意這個測試, 傳入一個 string, 和一個相似數組的對象
// 下面這個函數和 `foo${2 + 3}bar${'Java' + 'Script'}baz` 是相等的.
String.raw({
  raw: ['foo', 'bar', 'baz'] 
}, 2 + 3, 'Java' + 'Script'); // 'foo5barJavaScriptbaz'
複製代碼

ES6

ES6的新特性

  • let關鍵字,用於聲明只在塊級做用域起做用的變量
  • const關鍵字,用於聲明常量
  • 結構賦值,一種新的變量賦值方式
  • Symbol數據類型,定義一個獨一無二的值
  • for...of遍歷器,可遍歷具備iterator(迭代器)接口的數據類型
  • Set結構,用於存儲不重複成員值的集合
  • Map結構
  • Promise對象,一種異步操做的解決方案,更合理、規範的操做異步處理。
  • class類,定義類和更簡便的實現類的繼承
  • 模板字符串
  • 函數參數默認值
  • fetch

var、let、const的區別

  • var在任何語句執行前就完成了聲明和初始化
  • funciton聲明、初始化和賦值在一開始就所有完成,函數變量提高的優先級更高
  • let先聲明但並無初始化,只有解析到let那一行纔會進入初始化階段。若是在此做用域前提早訪問,則報錯xx is not defined , 暫時性死區,在相同做用域內不容許重複聲明同一個變量
  • constlet區別在於const聲明的是一個只讀常亮,一旦聲明後就不能改變

let const 優勢

  • 不會變量提高
  • 變量不能重複聲明
  • 有塊級做用域

es6 generator 是什麼,async/await 實現原理

ES6和node的commonjs模塊化規範區別

ES6 都有什麼 Iterator 遍歷器

一、遍歷器(Iterator)是一種接口,爲各類不一樣的數據結構提供統一的訪問機制。任何數據結構只要部署 Iterator 接口,就能夠完成遍歷操做(即依次處理該數據結構的全部成員)

二、Iterator 的做用有三個:

  • 一是爲各類數據結構,提供一個統一的、簡便的訪問接口;
  • 二是使得數據結構的成員可以按某種次序排列;
  • 三是 ES6 創造了一種新的遍歷命令 for...of 循環,Iterator 接口主要供 for...of 消費。

三、默認部署了 Iterator 的數據有 Array、Map、Set、String、TypedArray、arguments、NodeList 對象,ES6 中有的是 Set、Map、

ES6 中類的定義

// 一、類的基本定義
class Parent {
  constructor(name = "小白") {
    this.name = name;
  }
}
//=====================================
// 二、生成一個實例
let g_parent = new Parent();
console.log(g_parent); //{name: "小白"}
let v_parent = new Parent("v"); // 'v'就是構造函數name屬性 , 覆蓋構造函數的name屬性值
console.log(v_parent); // {name: "v"}

//=====================================
// 三、繼承
class Parent {
  //定義一個類
  constructor(name = "小白") {
    this.name = name;
  }
}

class Child extends Parent {}
console.log("繼承", new Child()); // 繼承 {name: "小白"}
//=====================================
// 四、繼承傳遞參數
class Parent {
  //定義一個類
  constructor(name = "小白") {
    this.name = name;
  }
}
class Child extends Parent {
  constructor(name = "child") {
    // 子類重寫name屬性值
    super(name); // 子類向父類修改 super必定放第一行
    this.type = "preson";
  }
}
console.log("繼承", new Child("hello")); // 帶參數覆蓋默認值 繼承{name: "hello", type: "preson"}
//=====================================
// 五、ES6從新定義的ES5中的訪問器屬性
class Parent {
  //定義一個類
  constructor(name = "小白") {
    this.name = name;
  }
  get longName() {
    // 屬性
    return "mk" + this.name;
  }
  set longName(value) {
    this.name = value;
  }
}

let v = new Parent();
console.log("getter", v.longName); // getter mk小白

v.longName = "hello";
console.log("setter", v.longName); // setter mkhello

//=====================================
// 六、類的靜態方法
class Parent {
  //定義一個類
  constructor(name = "小白") {
    this.name = name;
  }

  static tell() {
    // 靜態方法:經過類去調用,而不是實例
    console.log("tell");
  }
}

Parent.tell(); // tell

//=====================================
// 七、類的靜態屬性:
class Parent {
  //定義一個類
  constructor(name = "小白") {
    this.name = name;
  }
  static tell() {
    // 靜態方法:經過類去調用,而不是實例
    console.log("tell"); // tell
  }
}

Parent.type = "test"; // 定義靜態屬性
console.log("靜態屬性", Parent.type); // 靜態屬性 test
let v_parent = new Parent();
console.log(v_parent); // {name: "小白"} 沒有tell方法和type屬性
複製代碼

談談你對 ES6 的理解

es6 是一個新的標準,它包含了許多新的語言特性和庫,是 JS 最實質性的一次升級。

好比'箭頭函數'、'字符串模板'、'generators(生成器)'、'async/await'、'解構賦值'、'class'等等,還有就是引入 module 模塊的概念。

箭頭函數可讓 this 指向固定化,這種特性頗有利於封裝回調函數

  • (1)函數體內的 this 對象,就是定義時所在的對象,而不是使用時所在的對象。
  • (2)不能夠看成構造函數,也就是說,不可使用 new 命令,不然會拋出一個錯誤。
  • (3)不可使用 arguments 對象,該對象在函數體內不存在。若是要用,能夠用 Rest 參數代替。
  • (4)不可使用 yield 命令,所以箭頭函數不能用做 Generator 函數。
  • async/await 是寫異步代碼的新方式,之前的方法有回調函數和 Promise。
  • async/await 是基於 Promise 實現的,它不能用於普通的回調函數。async/await 與 Promise 同樣,是非阻塞的。
  • async/await 使得異步代碼看起來像同步代碼,這正是它的魔力所在。

promise的原理和實現

  • promise是同步執行的,promise.then是異步的
  • promise有三種狀態。pending、 fulfilled、rejected,狀態一旦改變就不會在變
  • resolve/reject屢次調用,只有第一次有效
  • promise每次調用都會返回一個新的promise,從而實現鏈式調用

解構賦值及其原理

  • ES6容許按照必定的規則,從數組或對象提取值,按照對應的位置對變量進行賦值

箭頭函數和普通函數的區別

  • 箭頭函數的語法定義要比普通函數簡潔,清晰。
  • 函數體內的this對象是定義是所在的對象,而不是使用時所在的對象
  • 不能夠當構造函數,也就是說不能用new命令
  • 函數體內不存在arguments對象。可使用參數代替
  • 不可使用yield命令。

es6的繼承和es5的繼承有什麼區別

  • ES5的繼承是經過原型或者構造函數實現的。
  • ES6封裝了class 用Extends來繼承

promise封裝ajax

function postJson(url, data) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('POST', url);
    xhr.onreadystatuschange = () => {
      if(xhr.readyState !== 4) return;
      if(xhr.status === 200) {
        resolve(xhr.responseText);
      } else {
        reject('請求失敗')
      }
    }
    xhr.send(JSON.stringify(data));
  })
}
複製代碼

Vue全家桶

Vue

vue中的key的做用

  • 帶key

key給每一個vnode(虛擬節點)增長一個惟一ID,在更新組件是判斷兩個節點是否相同。相同就複用,不相同就刪除舊建立新的。

雖然帶上key會增長開銷,可是對於用戶來講基本感覺不到差距,並且能保證組件狀態正確。

  • 不帶key

不帶key時節點可以複用,省去了銷燬/建立組件的開銷,同時只須要修改DOM文本內容而不是移除/添加節點。

這種模式diff速度可能會更快,但也會帶來一些隱藏的反作用,好比可能不會產生過渡效果,或者在某些節點有綁定數據(表單)狀態,會出現狀態錯位。 這種模式只適用於渲染簡單的無狀態組件

vue雙向數據綁定原理

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

具體步驟:

  • 第一步:須要 observe 的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 settergetter 這樣的話,給這個對象的某個值賦值,就會觸發setter,那麼就能監聽到了數據變化

  • 第二步:compile解析模板指令,將模板中的變量替換成數據,而後初始化渲染頁面視圖,並將每一個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變更,收到通知,更新視圖

  • 第三步:Watcher訂閱者是ObserverCompile之間通訊的橋樑,主要作的事情是:

    • 一、在自身實例化時往屬性訂閱器(dep)裏面添加本身
    • 二、自身必須有一個update()方法
    • 三、待屬性變更dep.notice()通知時,能調用自身的 update() 方法,並觸發Compile中綁定的回調,則功成身退。
  • 第四步:MVVM做爲數據綁定的入口,整合Observer、Compile和Watcher三者,經過Observer來監聽本身的model數據變化,經過Compile來解析編譯模板指令,最終利用Watcher搭起Observer和Compile之間的通訊橋樑,達到數據變化 -> 視圖更新;視圖交互變化(input) -> 數據model變動的雙向綁定效果。

Vue的生命週期

Vue生命週期一共分爲8個階段

  • 建立前/後
    • beforeCreated階段,實例的$eldatamethods都未初始化。this指向建立的實例
    • created階段,實例的datamethods都初始化完成,但 DOM節點還未掛載,不能訪問到$el屬性,$ref屬性爲空數組
  • 載入前/後
    • beforeMount階段,實例找到相對應的template並編譯成render函數
    • mouted階段,實例將el掛載到DOM上,能夠獲取到DOM節點,$ref屬性能夠訪問
  • 更新前/後
    • data變化時,會觸發beforeUpdateupdated
  • 銷燬前/後
    • 執行destroy方法後,data的改變不會再觸發周期函數,此時Vue實例已經解除了事件監聽DOM綁定,但DOM結構依然存在。

Vue 實例生命週期

Vue組件間的參數傳遞

  • 父傳子,父組件經過自定義綁定值,子組件經過props接收數據。
  • 子傳父,父組件經過on自定義事件綁定方法來接收值,子組件經過$emit觸發自定義事件傳遞參數給父組件
  • 非父子組件間的數據傳遞,兄弟組件傳值,用EventBus建立一個事件中心,用來傳遞/接收事件;
  • Vuex 狀態管理

keep-alive的做用是什麼

  • 包裹動態組件時,會緩存不活動的組件實例,主要用於保留組件狀態或避免從新渲染。

Vue性能優化

  • 打包優化
    • 小圖片轉base64

    • 靜態下圖片使用雪碧圖

    • 生成環境屏蔽sourceMap

    • 開啓gzip壓縮文件,減小文件大小

    • 第三方依賴按需加載

    • vue-router懶加載/異步路由

  • 代碼優化

    • 模板裏不寫過多表達式
    • 遍歷渲染列表數據時,爲每一項設置惟一的key值
    • 切換頻繁使用v-show,不頻繁使用v-if
    • 在適當的環境中使用keep-alive組件,用來緩存組件,避免屢次加載相應的組件,減小性能消耗。(tab切換)
    • 利用Object.freeze()提高性能
  • 用戶體驗優化
    • 移動端項目,click事件有300ms延遲,應使用touch事件
    • 資源加載完成前可使用loading動畫
    • 首屏加載資源較多,出現閃屏/白屏的狀況,可使用骨架屏

Vuex

什麼是Vuex

  • Vuex是一個專爲Vue服務,用於管理頁面數據狀態、提供統一數據操做的生態系統。

Vuex 原理

  • vuex 僅僅是做爲 vue 的一個插件而存在,不像 Redux,MobX 等庫能夠應用於全部框架,vuex 只能使用在 vue 上,很大的程度是由於其高度依賴於 vue 的 computed 依賴檢測系統以及其插件系統,
  • vuex 總體思想誕生於 flux,可其的實現方式完徹底全的使用了 vue 自身的響應式設計,依賴監聽、依賴收集都屬於 vue 對對象 Property set get 方法的代理劫持。最後一句話結束 vuex 工做原理,vuex 中的 store 本質就是沒有 template 的隱藏着的 vue 組件;

Vuex的特性

  • 每個Vuex應用的核心就是 store(倉庫)。「store」基本上就是一個容器,它包含着你的應用中大部分的狀態 (state)。
  • Vuex 和單純的全局對象有如下兩點不一樣:
    • Vuex 的狀態存儲是響應式的。當Vue組件從store中讀取狀態的時候,若store中的狀態發生變化,那麼相應的組件也會相應地獲得高效更新。
    • 你不能直接改變store中的狀態。改變store中的狀態的惟一途徑就是顯式地提交(commit)mutation。這樣使得咱們能夠方便地跟蹤每個狀態的變化,從而讓咱們可以實現一些工具幫助咱們更好地瞭解咱們的應用。

Vuex有哪些屬性

  • Vuex有五種屬性,分別是StateGetterMutationActionModule

Vuex的state特性

  • state爲單一狀態數,是數據源存放的地方(對應Vue對象裏的data),存放的數據是響應式的,Vue組件從store讀取數據,當store中的數據發生變化則依賴數據的組件也會發生變化。
  • 當一個組件須要獲取多個狀態時,可使用mapState輔助函數把state映射到組件的computed計算屬性上

Vuex的getter特性

  • 當須要從store的state中派生出一些狀態時,就須要使用getter.
  • getter的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變纔會被從新計算。

Vuex的mutation特性

  • 更改Store中狀態的惟一方式就是提交mutation。
  • mutation很是相似於事件
  • 每一個mutation都有一個事件類型(type)和回調函數(handler)
  • 要執行這個回調函數須要調用store.commit

Vuex的action特性

  • action相似於mutation,不一樣在於action提交的是mutation,而不能直接改變狀態。
  • action能夠包含任何異步操做
  • 若是須要調用action,則需經過store.dispatch觸發

Vuex的module特性

  • 使用單一狀態樹,致使應用的全部狀態集中到一個很大的對象,當應用變得很大時,store 對象會變得臃腫不堪。
  • 經過分割模塊,每一個模塊擁有本身的 state、mutation、action、getters、甚至是嵌套子模塊

ajax請求

  • 若是請求回來的數據若是被其餘組件複用則將請求放入action中,包裝成promise返回。
  • 若是不須要被其餘組件複用則能夠放在組件內部。

不用Vuex會帶來什麼問題

  • 可維護性會降低,你要想修改數據,你得維護三個地方(父組件屬性->子組件props->子組件))
  • 可讀性會降低,由於一個組件裏的數據,你根本就看不出來是從哪來的
  • 增長耦合,大量的上傳派發,會讓耦合性大大的增長,原本Vue用Component就是爲了減小耦合,如今這麼用,和組件化的初衷相背。
  • 兄弟組件有大量通訊的,建議必定要用,無論大項目和小項目,由於這樣會省不少事

VueRouter

懶加載/按需加載路由

  • 異步組件

    • 組件生成一個js文件
    • component: resolve => require(['../components/PromiseDemo'], resolve)
  • import

    • const ImportFuncDemo2 = () => import('../components/ImportFuncDemo2')
    • component: ImportFuncDemo2
  • webpackrequire.ensure()

    • 多個路由指定相同的chunkName,會合並打包成一個js文件
    • component: resolve => require.ensure([], () => resolve(require('../components/PromiseDemo')), 'demo')
  • 參考:vue項目按需加載

路由之間跳轉

  • 使用router-link 建立a標籤來定義導航連接
  • 編程式的導航 router.push router.push({ path: 'home' })

導航守衛

  • 全局守衛

    • 全局前置守衛 router.beforeEach
    • 全局解析守衛 router.beforeResolve (2.5.0 新增)
    • 全局後置守衛 router.afterEach
  • 路由獨享守衛

    • beforeEnter
  • 組件守衛

    • beforeRouteEnter
    • beforeRouteUpdate (2.2 新增)
    • beforeRouteLeave

怎麼定義 vue-router 的動態路由? 怎麼獲取傳過來的值

  • 在 router 目錄下的 index.js 文件中,對 path 屬性加上 /:id。
  • 使用 router 對象的 params.id 獲取

vue-router模式

  • hash
  • history

VueCli

重要 未寫

Vue源碼

項目中遇到的問題

微信小程序

1. 簡單描述下微信小程序的相關文件類型

微信小程序項目結構主要有四個文件類型

  • WXML: WeiXin Markup Language是框架設計的一套標籤語言,結合基礎組件、事件系統,能夠構建出頁面的結構。內部主要是微信本身定義的一套組件
  • WXSS: WeiXin Style Sheets 是一套樣式語言,用於描述 WXML 的組件樣式
  • js: 邏輯處理,網絡請求
  • json: 小程序設置,如頁面註冊,頁面標題及tabBar

主要文件

  • app.json 必需要有這個文件,若是沒有這個文件,項目沒法運行,由於微信框架把這個做爲配置文件入口,整個小程序的全局配置。包括頁面註冊,網絡設置,以及小程序的 window 背景色,配置導航條樣式,配置默認標題
  • app.js 必需要有這個文件,沒有也是會報錯!可是這個文件建立一下就行 什麼都不須要寫之後咱們能夠在這個文件中監聽並處理小程序的生命週期函數、聲明全局變量
  • app.wxss 可選

2. 簡述微信小程序原理

微信小程序採用 JavaScriptWXMLWXSS 三種技術進行開發,本質就是一個單頁面應用,全部的頁面渲染和事件處理,都在一個頁面內進行,但又能夠經過微信客戶端調用原生的各類接口

微信的架構,是數據驅動的架構模式,它的 UI 和數據是分離的,全部的頁面更新,都須要經過對數據的更改來實現

小程序分爲兩個部分 webviewappService 。其中 webview 主要用來展示 UIappService 有來處理業務邏輯、數據及接口調用。它們在兩個進程中運行,經過系統層 JSBridge 實現通訊,實現 UI 的渲染、事件的處理

3. 小程序的雙向綁定和vue哪裏不同

小程序直接 this.data 的屬性是不能夠同步到視圖的,必須調用:

this.setData({
    // 這裏設置
})
複製代碼

4. 小程序的wxss和css有哪些不同的地方

WXSSCSS 相似,不過在 CSS 的基礎上作了一些補充和修改

  • 尺寸單位 rpx

rpx 是響應式像素,能夠根據屏幕寬度進行自適應。規定屏幕寬爲 750rpx。如在 iPhone6 上,屏幕寬度爲 375px,共有 750 個物理像素,則 750rpx = 375px = 750 物理像素

  • 使用 @import 標識符來導入外聯樣式。@import 後跟須要導入的外聯樣式表的相對路徑,用;表示語句結束
/** index.wxss **/
@import './base.wxss';

.container{
    color: red;
}
複製代碼

5. 小程序頁面間有哪些傳遞數據的方法

  • 使用全局變量實現數據傳遞 在 app.js 文件中定義全局變量 globalData, 將須要存儲的信息存放在裏面
// app.js

App({
     // 全局變量
  globalData: {
    userInfo: null
  }
})
複製代碼

使用的時候,直接使用 getApp() 拿到存儲的信息

  • 使用 wx.navigateTowx.redirectTo 的時候,能夠將部分數據放在 url 裏面,並在新頁面 onLoad 的時候初始化
//pageA.js

// Navigate
wx.navigateTo({
  url: '../pageD/pageD?name=raymond&gender=male',
})

// Redirect
wx.redirectTo({
  url: '../pageD/pageD?name=raymond&gender=male',
})


// pageB.js
...
Page({
  onLoad: function(option){
    console.log(option.name + 'is' + option.gender)
    this.setData({
      option: option
    })
  }
})
複製代碼

須要注意的問題:

wx.navigateTowx.redirectTo 不容許跳轉到 tab 所包含的頁面

onLoad 只執行一次

  • 使用本地緩存 Storage 相關

6. 小程序的生命週期函數

  • onLoad 頁面加載時觸發。一個頁面只會調用一次,能夠在 onLoad 的參數中獲取打開當前頁面路徑中的參數
  • onShow() 頁面顯示/切入前臺時觸發
  • onReady() 頁面初次渲染完成時觸發。一個頁面只會調用一次,表明頁面已經準備穩當,能夠和視圖層進行交互
  • onHide() 頁面隱藏/切入後臺時觸發。 如 navigateTo 或底部 tab 切換到其餘頁面,小程序切入後臺等
  • onUnload() 頁面卸載時觸發。如 redirectTonavigateBack 到其餘頁面時

詳見 生命週期回調函數

. 怎麼封裝微信小程序的數據請求

wx.request({
  url: 'test.php', //僅爲示例,並不是真實的接口地址
  data: {
     x: '' ,
     y: ''
  },
  success: function(res) {
    console.log(res.data)
  }
})
// promise

複製代碼

參考 這裏

8. 哪些方法能夠用來提升微信小程序的應用速度

一、提升頁面加載速度

二、用戶行爲預測

三、減小默認 data 的大小

四、組件化方案

9. 微信小程序的優劣勢

優點

  • 即用即走,不用安裝,省流量,省安裝時間,不佔用桌面
  • 依託微信流量,天生推廣傳播優點
  • 開發成本比 App

缺點

  • 用戶留存,即用即走是優點,也存在一些問題
  • 入口相對傳統 App 要深不少
  • 限制較多,頁面大小不能超過2M。不能打開超過10個層級的頁面

10. 怎麼解決小程序的異步請求問題

小程序支持大部分 ES6 語法

  • 在返回成功的回調裏面處理邏輯
  • Promise 異步

11. 小程序關聯微信公衆號如何肯定用戶的惟一性

若是開發者擁有多個移動應用、網站應用、和公衆賬號(包括小程序),可經過 unionid來區分用戶的惟一性,由於只要是同一個微信開放平臺賬號下的移動應用、網站應用和公衆賬號(包括小程序),用戶的 unionid 是惟一的。換句話說,同一用戶,對同一個微信開放平臺下的不一樣應用,unionid 是相同的

12. 如何實現下拉刷新

  • 首先在全局 config 中的 window 配置 enablePullDownRefresh
  • Page 中定義 onPullDownRefresh 鉤子函數,到達下拉刷新條件後,該鉤子函數執行,發起請求方法
  • 請求返回後,調用 wx.stopPullDownRefresh 中止下拉刷新

參考 這裏

13. bindtap和catchtap的區別是什麼

相同點:首先他們都是做爲點擊事件函數,就是點擊時觸發。在這個做用上他們是同樣的,能夠不作區分

不一樣點:他們的不一樣點主要是 bindtap 是不會阻止冒泡事件的,catchtap 是阻值冒泡的

14. 簡述下 wx.navigateTo(), wx.redirectTo(), wx.switchTab(), wx.navigateBack(), wx.reLaunch()的區別

  • wx.navigateTo():保留當前頁面,跳轉到應用內的某個頁面。可是不能跳到 tabbar 頁面
  • wx.redirectTo():關閉當前頁面,跳轉到應用內的某個頁面。可是不容許跳轉到 tabbar 頁面
  • wx.switchTab():跳轉到 abBar 頁面,並關閉其餘全部非 tabBar 頁面
  • wx.navigateBack()關閉當前頁面,返回上一頁面或多級頁面。可經過 getCurrentPages() 獲取當前的頁面棧,決定須要返回幾層
  • wx.reLaunch():關閉全部頁面,打開到應用內的某個頁面

React全家桶

  • 基本語法
  • 生命週期

框架

  • bootstrap
  • element
  • Echarts
  • Swiper

Node\Express\Egg\Koa

  • 熟悉幾道經常使用面試題

開發中遇到的問題

爲何 0.1 + 0.2 != 0.3 ?

JS 採用的是雙精度版本

  • 內部的原理是什麼?

咱們計算機的信息所有轉化爲二進制進行存儲的,那麼0.1的二進制表示的是一個無限循環小數, 該版本的 JS 採用的是浮點數標準須要對這種無限循環的二進制進行截取,從而致使了精度丟失, 形成了0.1再也不是0.1,截取以後0.1變成了 0.100...001,0.2變成了0.200...002。因此二者相加的數大於0.3。

  • 控制檯上輸出console.log(0.1)還等於0.1?

由於在輸入內容進行轉換的時候,二進制轉換成十進制,而後十進制轉換成字符串, 在這個轉換的過程當中發生了取近似值,因此打印出來的是一個近似值。

部分手機第三方輸入法會將頁面網上擠的問題

// 特定需求頁面,好比評論頁面,輸入框在頂部之類的
const interval = setInterval(function() {
    document.body.scrollTop = 0;
}, 100)
// 注意關閉頁面或者銷燬組件的時候記得清空定時器
clearInterval(interval);
複製代碼
  • 設置一個100ms的定時器,把scrollTop設置成0,當點擊完成是清空定時器

ios豎屏拍照上傳,圖片被旋轉問題

flex對低版本的ios和Android的支持問題

/**使用postcss的autoprefixer插件,自動添加瀏覽器內核前綴, 而且增長更低瀏覽器版本的配置,自動添加flex老版本的屬性和寫法**/
autoprefixer({
    browsers: [
        'iOS >= 6',     // 特殊處理支持低版本IOS
        'Safari >= 6',  // 特殊處理支持低版本Safari
    ],
}),
複製代碼

ios上自動識別電話

<meta content="telephone=no" name="format-detection" />
複製代碼

android上自動識別郵箱

<meta content="email=no" name="format-detection" />
複製代碼

移動端click300ms延遲

緣由:click事件要等待是不是雙擊事件,會有300ms的延遲

解決:使用touchstart/touchend或者使用zepto的tap事件替代click

圖片優化

  • 小圖片過多,致使請求增多
    • 使用精靈圖合併成大圖,缺點: 若是換圖的化很是麻煩
    • 把圖標轉成base64
  • 首屏加載慢,到時用戶體驗極差
    • 圖片懶加載,
    • 靜態資源放到CDN
相關文章
相關標籤/搜索