js進階的學習筆記

數據類型分類

  • 基本(值)類型css

    String,Number,boolean,undefined,nullhtml

  • 對象(引用)類型vue

    Object:任意對象程序員

    Function:一種特別的對象(能夠執行)es6

    Array:一種特別的對象(數值下標,內部數據是有序的)ajax

數據類型的判斷

  • typeof 返回數據類型的字符串表達跨域

    能夠判斷undefined / 數值 / 字符串/布爾值瀏覽器

    不能判斷nullobject緩存

  • instanceof 返回布爾值markdown

  • ===能夠判斷undefinednull

  1. undefinednull的區別?

    undefined表明定義未賦值

    null定義並賦值了,只是值爲null

  2. 何時給變量賦值爲null呢?

    • 初始賦值,代表將要賦值爲對象。

    • 結束前,被垃圾回收器回收

  3. 嚴格區別變量類型與數據類型?

    • 數據的類型

      • 基本類型

      • 對象類型

    • 變量的類型(變量內存值的類型)

      • 基本類型:保存基本類型的數據

      • 引用類型:保存的是地址值

  4. 什麼是數據?

    • 存儲在內存中表明特定信息的,本質上是0101...

    • 數據的特色:可傳遞,可運算

    • 一切皆數據

  5. 內存中全部操做的目標:

    • 數據

    • 算術運算

    • 邏輯運算

    • 賦值

    • 運行函數

  6. 什麼是內存?

    • 內存條通電之後產生的可存儲數據的空間。(臨時的)

    • 內存的產生和死亡:內存條(電路板)-->產生內存空間-->存儲數據-->斷電-->內存空間和數據都消失

    • 一塊小內存的兩個數據

      • 內部存儲的數據

      • 地址值

  7. 內存分類

    • 棧:全局變量和局部變量(空間較小)

    • 堆:對象(空間較大)

  8. 什麼是變量?

    • 可變化的量,由變量名和變量值組成

    • 每一個變量都對應的一塊小內存,變量名用來查找對應的內存,變量值就是內存中保存的數據。

  9. 內存,數據,變量三者之間的關係

    • 內存用來存儲數據的空間

    • 變量是內存的標識

  10. 問題:var a = xxxa內存中保存的是什麼?

    • xxx是基本數據,保存的是這個數據

    • xxx是對象,保存的是對象的地址值

    • xxx是一個變量,保存xxx的內存內容(多是基本數據,也多是地址值)

  11. 關於引用變量賦值問題

    • n個引用變量指向同一個對象,經過一個變量修改對象內部數據,另外一個變量看到的是修改以後的數據。

    • n個引用變量指向同一個對象,讓其中一個引用變量指向另外一個對象,另外一個引用變量依然指向前一個對象。

  12. 問題:在js調用函數時傳遞變量參數時,是值傳遞仍是引用傳遞?

    • 理解1:都是值(基本值/地址值)傳遞

    • 理解2:多是值傳遞,也多是引用傳遞(地址值)

  13. 問題:js引擎如何管理內存?

    1. 內存生命週期

      • 分配小內存空間,獲得它的使用權

      • 存儲數據,能夠反覆進行操做

      • 釋放小內存空間

    2. 釋放內存

      • 局部變量:函數執行完自動釋放(棧空間)

      • 對象:成爲垃圾對象-->垃圾回收器回收(堆空間)

  14. 什麼是對象?

    • 多個數據的封裝體

    • 用來保存多個數據的容器

    • 一個對象表明現實世界中的一個事物

  15. 爲何要用對象?

    • 統一管理多個數據
  16. 對象的組成

    • 屬性:屬性名(字符串)和屬性值(任意類型)組成。

    • 方法:一種特別的屬性(屬性值是函數)

  17. 如何訪問對象內部數據?

    • .屬性名:編碼簡單,有時不能用

    • ['屬性名']:編碼麻煩,能通用

  18. 問題:何時必須使用['屬性名']的方式?

    1. 屬性名包含特殊字符:-,空格

    2. 變量名不肯定

  19. 什麼是函數?

    • 實現特定功能的n條語句的封裝體

    • 只有函數是能夠執行的,其餘類型的數據不能執行

  20. 爲何要用函數?

    • 提升代碼複用

    • 便於閱讀交流

  21. 如何定義函數?

    • 函數聲明

    • 表達式

  22. 如何調用(執行)函數?

    • test():直接調用

    • obj.test():經過對象調用

    • new test():new調用

    • test.call/apply(obj):臨時讓test成爲obj的方法進行調用

  23. 什麼函數纔是回調函數?

    1. 本身定義的

    2. 本身沒有調用

    3. 但最終執行了(在某個時刻或某個條件下)

  24. 常見的回調函數?

    • dom事件回調函數 this ==>發生事件的dom元素

    • 定時器回調函數 this==>window

    • ajax請求回調函數

    • 聲明週期回調函數

  25. IIFE的理解

    • 全稱:Immediately-Invoked Function Expression 當即調用函數表達式

    • 也能夠叫:匿名函數自調用

  26. IIFE的做用

    • 隱藏實現

    • 不會污染外部(全局)命名空間

    • 用它來編碼js模塊

  27. this是什麼?

    • 任何函數本質上都是經過某個對象來調用的,若是沒有直接指定的就是window

    • 全部函數內部都有一個變量this

    • 它的值是調用函數的當前對象

  28. 如何肯定this的值?

    test():window

    p.test():p

    new test():新建立的對象

    p.call(obj):obj

  29. js一條語句的後面能夠不加分號

  30. 是否加分號是編碼風格問題,沒有應不該該,只有喜不喜歡

  31. 在下面2種狀況下不加分號會有問題

    • 小括號開頭的前一條語句

    • 中方括號開頭的前一條語句

  32. 解決辦法:在行首加分號

  33. 例子:vue.js庫

函數的prototype屬性

  1. 每一個函數都有一個prototype屬性,他默認指向一個Object空對象(稱爲:原型對象)

  2. 原型對象中有一個屬性constructor ,他指向函數對象

  3. 給原型對象添加屬性(通常都是方法)

    做用:函數的全部實例對象自動擁有原型中的屬性(方法)

  4. 每一個函數function都有一個prototype,即顯式原型

  5. 每一個實例對象都有一個__proto__,可稱爲隱式原型

  6. 對象的隱式原型的值爲其對應構造函數的顯式原型的值

  7. 總結:

    函數的prototype屬性:在定義函數時自動添加的,默認值是一個空Object對象。

    對象的__proto__屬性:建立對象時自動添加的,默認值爲構造函數的prototype屬性值。

    程序員能直接操做顯式原型,但不能直接操做隱式原型(es6以前)

訪問一個對象的屬性時,

原型鏈

  • 訪問一個對象的屬性時,如今自身屬性中查找,找到返回。若是沒有,再沿着__proto__這條鏈向上查找,找到返回。若是最終沒有找到,返回undefined

  • 別名:隱式原型鏈

  • 做用:查找對象的屬性(方法)

779716f56e53135703ddc785f3ee749.png

  • 全部函數的__proto__都是同樣的
  • 實例對象的隱式原型=構造對象的顯式原型
  1. 函數的顯式原型指向的對象默認是空Object實例對象(但Object不知足)

  2. 全部函數都是Function的實例(包括Function

  3. Object的原型對象是原型鏈的盡頭,Object.__proto__ =null

  4. 讀取對象的屬性值時:會自動到原型鏈中查找

  5. 設置對象的屬性值時:不會查找原型鏈,若是當前對象中沒有此屬性,直接天界此屬性並設置其值。

  6. 方法通常定義在原型中,屬性通常經過構造函數定義在對象自己上。

1.instanceof是如何判斷的?

表達式「A instanceof B

若是B函數的顯式原型對象在A對象的原型鏈上,返回true,不然返回false

變量聲明提高

經過var定義(聲明)的變量,在定義語句以前就能夠訪問到

值:undefined

函數聲明提高

經過function聲明的函數,在以前就能夠直接調用(var定義的不行)

值:函數定義(對象)

代碼分類(位置)

全局代碼

函數(局部)代碼

全局執行上下文

在執行全局代碼前將window肯定爲全局執行上下文

對全局數據進行預處理

  • var定義的全局變量==>undefined,添加爲window的屬性

  • function聲明的全局函數==>賦值(fun),添加爲window的方法

  • this==>賦值(window)

    開始執行全局代碼

函數執行上下文(函數調用時產生)

  • 在調用函數,準備執行函數體以前,建立對應的函數執行上下文對象(虛擬的,存在於棧中)

  • 對局部數據進行預處理

  • 形參變量==>賦值(實參)==>添加爲執行上下文的屬性

  • arguments==>賦值(實參列表),添加爲執行上下文的屬性

  • var定義的局部變量==>undefined,添加爲執行上下文的屬性

  • function聲明的函數==>賦值(fun),添加爲執行上下文的方法

  • this==>賦值(調用函數的對象)

    開始執行函數體代碼

  1. 在全局代碼執行前,js引擎就會建立一個棧來存儲管理全部的執行上下文對象

  2. 在全局執行上下文(window)肯定後,將其添加到棧中(壓棧)

  3. 在函數執行上下文建立後,將其添加到棧中(壓棧)

  4. 在當前函數執行完後,將棧頂的對象移除(出棧)

  5. 當全部的代碼執行完後,棧中只剩下爲window

    先執行變量提高,再執行函數提高

    遞歸調用:在函數內部調用本身

做用域的理解

  • 就是一塊「地盤」,一個代碼段所在的區域

  • 它是靜態的(相對於上下文對象),在編寫代碼時就肯定了

  • 分類

    • 全局做用域

    • 函數做用域

    • 沒有塊做用域(es6有了)

  • 做用

    • 隔離變量,不一樣做用域下同名變量不會有衝突

做用域與執行上下文

  1. 全局做用域以外,每一個函數都會建立本身的做用域,做用域在函數定義時就已經肯定了,而不是在函數調用時。

    全局執行上下文環境是在全局做用域肯定以後,js代碼立刻執行前建立。

    函數執行上下文環境是在調用函數時,函數體代碼執行以前建立。

  2. 做用域是靜態的,只要函數定義好了就一直存在,且不會變化。

    上下文環境是動態的,調用函數時建立,函數調用結束時上下文環境就會自動釋放。

  3. 聯繫

    上下文環境(對象)是從屬於所在的做用域

    全局上下文環境==>全局做用域

    函數上下文環境==>對應的函數使用域

做用域鏈的理解

多個上下級關係的做用域造成的鏈,它的方向是從下向上的(從內向外)

查找變量時就是沿着做用域鏈來查找的

查找一個變量的查找規則

在當前做用域下的執行上下文中查找對應的屬性,若是還找不到就拋出找不到的異常。

閉包

  1. 如何產生閉包?

    當一個嵌套的內部(子)函數引用了嵌套的外部(子)函數的變量(函數)時,就產生了閉包

  2. 閉包究竟是什麼?

    使用Chrome調試查看

    理解一:閉包是嵌套的內部函數(絕大多部分人)

    理解二:包含被引用變量(函數)的對象(極少數人)

    注意:閉包存在於嵌套的內部函數中

  3. 產生閉包的條件?

    函數嵌套

    內部函數引用了外部函數的數據(變量/函數)

  4. 常見的閉包

    1. 將函數做爲另外一個函數的返回值

    2. 將函數做爲實參傳遞給另外一個函數調用

  5. 閉包的做用

    1. 使用函數內部的變量在函數執行完後,仍然存活在內存中(延長了局部變量的生命週期)

    2. 讓函數外部均可以操做(讀寫)到函數內部的數據(變量/函數)

  6. 問題:

    1. 函數執行完後,函數內部聲明的局部變量是否還存在?

    通常是不存在,存在於閉包中的變量纔可能存在

    1. 在函數外部能直接訪問函數內部的局部變量嗎?

    不能,可是能夠經過閉包讓外部操做它。

  7. 閉包的生命週期

    1. 產生:在嵌套內部函數定義執行完時就產生了(不是在調用)

    2. 死亡:在嵌套的內部函數成爲垃圾對象時

  8. 閉包的應用:定義js模塊

    具備特定功能的js文件

    將全部的數據和功能都封裝在一個函數內部(私有的)

    只向外暴露一個包含n個方法的對象或函數

    模塊的使用者,只須要經過模塊暴露的對象調用方法來實現對應的功能。

06.jpg 9. 閉包的缺點及解決

  1. 缺點

    • 函數執行完後,函數內的局部變量沒有釋放,佔用內存時間會變長

    • 容易形成內存泄露

  2. 解決

    • 能不用閉包就不用閉包

    • 及時釋放

內存溢出

  • 一種程序運行出現的錯誤

  • 當程序運行須要的內存超過了剩餘的內存時,就會拋出內存溢出的錯誤

內存泄露

  • 佔用的內存沒有及時釋放

  • 內存泄露積累多了就會容易致使內存溢出

  • 常見的內存泄漏:

    • 意外的全局變量

    • 沒有及時清理的計時器或回調函數

    • 閉包

建立函數

  1. Object構造函數模式

    套路:先建立空Object對象,再動態添加屬性/方法

    適用場景:起始時不肯定對象內部數據

    問題:語句太多

  2. 對象字面量模式

    套路:使用{ }建立對象,同時指定屬性/方法

    適用場景:起始時對象內部數據時肯定的

    問題:若是建立多個對象,有重複代碼

  3. 工廠模式

    套路:經過工廠函數動態建立對象並返回

    適用場景:須要建立多個對象

    問題:對象沒有一個具體的類型,都是Object類型

  4. 自定義構造函數模式

    套路:自定義構造函數,經過new建立對象

    適用場景:須要建立多個類型肯定的對象

    問題:每一個對象都有相同的數據,浪費內存

  5. 構造函數+原型的組合模式

    套路:自定義構造函數,屬性在函數中初始化,方法添加到原型上

    適用場景:須要建立多個類型肯定的對象

原型鏈繼承

  1. 套路

    1. 定義父類型構造函數

    2. 給父類型的原型添加方法

    3. 定義子類型的構造函數

    4. 建立父類型的對象賦值給子類型的原型

    5. 將子類型原型的構造屬性設置爲子類型

    6. 給子類型原型添加方法

    7. 建立子類型的對象:能夠調用父類型的方法

  2. 關鍵

    1. 子類型的原型爲父類型的一個實例對象
function Parent(){ }

Parent.prototype.test = function(){ };

function Child( ){ }

Child.prototype = new Parent( );//子類型的原型指向父類型實例

Child.prototype.constructor = Child

var child = new Child( );

借用構造函數繼承(假的):獲得屬性

複製代碼
  1. 套路:

    1. 定義父類型構造函數

    2. 定義子類型構造函數

    3. 在子類型構造函數中調用父類型構造

  2. 關鍵:

    1. 在子類型構造函數中通用call ()調用父類型構造函數
function Parent(xxx){ this.xxx = xxx}

Parent.prototype.test = function( ){ };

function Child(xxx,yyy){

    Parent.call(this,xxx)// 借用構造函數 this.Parent(xxx)

}

var child =new Child('a','b'); //child.xxx爲'a',但child沒有test()

複製代碼

原型鏈+借用構造函數的組合繼承

  1. 利用原型鏈實現對父類型對象的方法繼承

  2. 利用super()借用父類型構建函數初始化相同屬性

function Parent(xxx){this.xxx=xxx}

Parent.prototype.test = function(){};

function Child(xxx,yyy){

    Parent.call(this,xxx);//借用構造函數 this.Parent(xxx)

}

Child.prototype = new Parent();//獲得test()

var child = new Child();//child.xxx爲'a',也有test()
複製代碼

new一個對象作了什麼?

建立一個空對象

給對象設置__proto__,值爲構造函數對象的prototype屬性值,this.__proto__=Fn.prototype

執行構造函數體(給對象添加屬性/方法)

線程

線程池:保存多個線程對象的容器,實現線程對象的反覆利用

  • 多線程

    • 優勢:能有效提高CPU的利用率,建立多線程開銷

    • 缺點:線程間切換開銷,死鎖與狀態同步問題

  • js是單線程仍是多線程?

    • js是單線程運行的

    • 但使用H5中的Web Workers能夠多線程運行

  • 瀏覽器內核由不少模塊組成

    主線程

    • js引擎模塊:負責js程序的編譯與運行

    • html,css文檔解析模塊:負責頁面文本的解析

    • DOM/CSS模塊:負責dom/ css在內存中的相關處理

    • 佈局和渲染模塊:負責頁面的佈局和效果的繪製(內存中的對象)

    分線程

    • 定時器模塊:負責定時器的管理

    • 事件響應模塊:負責事件的管理

    • 網絡請求模塊:負責ajax請求

  1. 定時器真是定時執行的嗎?

    • 定時器並不能保證真正定時執行

    • 通常會延遲一丁點(能夠接受),也有可能延遲很長時間(不能接受)

  2. 定時器回調函數是在分線程執行的嗎?

    • 在主線程執行的,js是單線程的
  3. 定時器是如何實現的?

    • 事件循環模型
  • alert會暫停當前的主線程的執行,同時暫停計時,點擊肯定後,恢復程序執行和計時

  • alertwindow的方法,在分線程不能調用

  1. 如何證實js執行時單線程的?

    • setTimeout()的回調函數是在主線程執行的

    • 定時器回調函數只有在運行棧中的代碼所有執行完後纔有可能執行

  2. 爲何js要用單線程模式,而不用多線程模式?

    • js的單線程和它的用途有關

    • 做爲瀏覽器腳本語言,js的主要用途是魚用戶互動,以及操做dom

    • 這決定了他只能是單線程,不然會帶來很複雜的同步問題

  3. 代碼的分類

    • 初始化代碼(同步代碼):包含綁定dom事件監聽,設置定時器,發送ajax請求的代碼

    • 回調代碼(異步代碼):處理回調邏輯

  4. js引擎執行代碼的基本流程

    • 先執行初始化代碼:包含一些特別的代碼 回調函數(異步執行)

    • 設置定時器

    • 綁定監聽

    • 發送ajax請求

    • 後面在某個時刻纔會執行回調代碼

  5. 模型的2個重要組成部分:

    • 事件管理模塊

    • 回調隊列(起到了一個緩存的做用)

  6. 模型的運轉流程

    • 執行初始化代碼,將事件回調函數交給對象模塊管理

    • 當事件發生時,管理模塊會將回調函數及其數據添加到回調隊列中

    • 只有當初始化代碼執行完後(可能要必定時間),纔會遍歷讀取回調隊列中的回調函數執行

    • 事件輪詢(event loop):從任務隊列中循環取出回調函數放入執行棧處理中

  7. H5規範提供了js分線程的實現,取名爲:Web Workers

  8. 相關API

    • Worker:構造函數,加載分線程執行的js文件

    • Worker.prototype.onmessage:用於接收另外一個線程的回調函數

    • Worker.prototype.postMessage:向另外一個線程發送消息

    • worker.onMessage=function(event){event.data}:用來接受另外一個線程發送過來的數據的回調

  9. 不足

    • worker內代碼不能操做DOM(更新UI)

    • 不能跨域加載js

    • 不是每一個瀏覽器都支持這個新特性

相關文章
相關標籤/搜索