前端複習要點

漲月薪發表於2019-04-01

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

一、HTML&CSS

1.文字溢位顯示省略號

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

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

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

text-overflow:ellipsis:單行文字的溢位顯示省略號

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

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

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

常見結合屬性:

  • display: -webkit-box:必須結合的屬性,將物件作為彈性伸縮盒子模型顯示 。
  • -webkit-box-orient:必須結合的屬性,設定或檢索伸縮盒物件的子元素的排列方式 。

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度,從藍色漸變到紅色 */

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

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)

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

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可以控制的


二、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.js中的強制型別轉換

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

4.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')
複製程式碼

5.null和undefined的區別

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

6.陣列物件有哪些常用方法

修改器方法:詳細可參考: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(): 返回一個由回撥函式的返回值組成的新陣列

7.js中宣告提升、作用域(鏈)、this關鍵字和箭頭函式

參考:juejin.im/published

AJAX、$.ajax、axios、fetch、superagent

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

js事件模型 事件委託

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

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

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

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

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

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

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

【事件傳播的阻止方法】

在W3C中,使用stopPropagation()方法

在IE下使用cancelBubble = true方法

【阻止預設行為】

在W3c中,使用preventDefault()方法

在IE下return false

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

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

優點:

  • 只需要將同類元素的事件委託給父級或者更外級的元素,不需要給所有元素都繫結事件,減少記憶體空間佔用,提升效能 無需為子節點登出事件。
  • 動態新增的元素無需重新繫結事件

閉包-迴圈定時器問題

參考:juejin.im/post/58f1fa…

js排序演算法詳解

參考:mp.weixin.qq.com/s/gR0kCPRgQ…

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])
    }
}
複製程式碼

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 Animal {
    
}

class Cat extends Animal {
    constructor() {
        super();
  }
}
複製程式碼

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');
}
複製程式碼

深淺拷貝

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);
複製程式碼

前端效能優化

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

相關文章