# 前端雜貨鋪

Javascript高級程序設計

最近想把Javascript再擼一篇,加深理解。所以在啃Javascript高級程序設計。在這里記錄下那些易遺忘的知識點記錄下來,方便以后回顧。會一直更新

1.瀏覽器作用

瀏覽器的主要功能就是向服務器發出請求,在瀏覽器窗口中展示您選擇的網絡資源。這里所說的資源一般是指 HTML 文檔,也可以是 PDF、圖片或其他的類型。資源的位置由用戶使用 URI(統一資源標示符)指定。

2.瀏覽器高層結構

     1. 用戶界面 - 包括地址欄、前進/后退按鈕、書簽菜單等。除了瀏覽器主窗口顯示的您請求的頁面外,其他顯示的各個部分都屬于用戶界面。
     2. 瀏覽器引擎 - 在用戶界面和呈現引擎之間傳送指令。
     3. 呈現引擎 - 負責顯示請求的內容。如果請求的內容是 HTML,它就負責解析 HTML 和 CSS 內容,并將解析后的內容顯示在屏幕上。
     4. 網絡 - 用于網絡調用,比如 HTTP請求。其接口與平臺無關,并為所有平臺提供底層實現。
     5. 用戶界面后端 - 用于繪制基本的窗口小部件,比如組合框和窗口。其公開了與平臺無關的通用接口,而在底層使用操作系統的用戶界面方法。
     6. JavaScript 解釋器。用于解析和執行 JavaScript 代碼。
     7. 數據存儲。這是持久層。瀏覽器需要在硬盤上保存各種數據,例如 Cookie。新的 HTML 規范 (HTML5) 定義了“網絡數據庫”,這是一個完整(但是輕便)的瀏覽器內數據庫。

3.主流程

    呈現引擎將開始**解析 HTML 文檔**,并將各標記逐個轉化成“內容樹”上的 DOM 節點。同時也會解析外部 CSS 文件以及樣式元素中的樣式數據。HTML 中這些帶有視覺指令的樣式信息將用于創建另一個樹結構:呈現樹。
    
    呈現樹包含多個帶有視覺屬性(如顏色和尺寸)的矩形。這些矩形的排列順序就是它們將在屏幕上顯示的順序。
    
    呈現樹構建完畢之后,進入“布局”處理階段,也就是為每個節點分配一個應出現在屏幕上的確切坐標。下一個階段是繪制 - 呈現引擎會遍歷呈現樹,由**用戶界面后端層將每個節點繪制出來。
    
    需要著重指出的是,這是一個漸進的過程。為達到更好的用戶體驗,呈現引擎會力求盡快將內容顯示在屏幕上。它不必等到整個 HTML 文檔解析完畢之后,就會開始構建呈現樹和設置布局。在不斷接收和處理來自網絡的其余內容的同時,呈現引擎會將部分內容解析并顯示出來。

4.什么是JavaScript解析引擎?

   簡單地說,JavaScript解析引擎就是能夠“讀懂”JavaScript代碼,并準確地給出代碼運行結果的一段程序。比方說,當你寫了 var a = 1 + 1; 這樣一段代碼,JavaScript引擎做的事情就是看懂(解析)你這段代碼,并且將a的值變為2。

  學過編譯原理的人都知道,對于靜態語言來說(如Java、C++、C),處理上述這些事情的叫編譯器(Compiler),相應地對于JavaScript這樣的動態語言則叫解釋器(Interpreter)。這兩者的區別用一句話來概括就是:編譯器是將源代碼編譯為另外一種代碼(比如機器碼,或者字節碼),而解釋器是直接解析并將代碼運行結果輸出。比方說,firebug的console就是一個JavaScript的解釋器。

   但是,現在很難去界定說,JavaScript引擎它到底算是個解釋器還是個編譯器,因為,比如像V8(Chrome的JS引擎),它其實為了提高JS的運行性能,在運行之前會先將JS編譯為本地的機器碼(native machine code),然后再去執行機器碼(這樣速度就快很多),相信大家對JIT(Just In Time Compilation)一定不陌生吧。

   我個人認為,不需要過分去強調JavaScript解析引擎到底是什么,了解它究竟做了什么事情我個人認為就可以了。對于編譯器或者解釋器究竟是如何看懂代碼的,翻出大學編譯課的教材就可以了。

   這里還要強調的就是,JavaScript引擎本身也是程序,代碼編寫而成。比如V8就是用C/C++寫的。

5. JavaScript解析引擎與ECMAScript是什么關系?

    JavaScript引擎是一段程序,我們寫的JavaScript代碼也是程序,如何讓程序去讀懂程序呢?這就需要定義規則。比如,之前提到的var a = 1 + 1;,它表示:
    
    左邊var代表了這是申明(declaration),它申明了a這個變量
    右邊的+表示要將1和1做加法
    中間的等號表示了這是個賦值語句
    最后的分號表示這句語句結束了
    上述這些就是規則,有了它就等于有了衡量的標準,JavaScript引擎就可以根據這個標準去解析JavaScript代碼了。那么這里的ECMAScript就是定義了這些規則。其中ECMAScript 262這份文檔,就是對JavaScript這門語言定義了一整套完整的標準。其中包括:
    
    var,if,else,break,continue等是JavaScript的關鍵詞
    abstract,int,long等是JavaScript保留詞
    怎么樣算是數字、怎么樣算是字符串等等
    定義了操作符(+,-,>,<等)
    定義了JavaScript的語法
    定義了對表達式,語句等標準的處理算法,比如遇到==該如何處理
    ??
    
    標準的JavaScript引擎就會根據這套文檔去實現,注意這里強調了標準,因為也有不按照標準來實現的,比如IE的JS引擎。這也是為什么JavaScript會有兼容性的問題。

簡單的說,ECMAScript定義了語言的標準,JavaScript引擎根據它來實現,這就是兩者的關系。

6.input="type='number'"會有滾輪

去除瀏覽器默認樣式

    input::-webkit-outer-spin-button,  //谷歌瀏覽器
    input::-webkit-inner-spin-button {  
        -webkit-appearance: none;  
    }  
  
    input[type="number"] {  //火狐瀏覽器
        -moz-appearance: textfield;  
    }

7.javascirpt嚴格模式use-strict

嚴格模式為javascript定義了一種不同的解析和執行模型。在嚴格模式下,ECMAscript3中的一些不確定的行為將得到處理,而且對某些不安全的操作也會拋出錯誤。給未經申明的變量賦值在嚴格模式下會報ReferenceError 錯誤。

    1.腳本頂部:"use strict";
    2.函數體頂部:function doSomething(){
        "use strict";
    }

8.NaN

JS中,0除以0是NaN,正數除以0為Infinity,負數除以0為-Infinity因此不會影響其他代碼的執行。

  • [x] 任何涉及NaN的操作都將返回NaN
  • [x] NaN與任何值都不相等,包括自身
    console.log(NaN == NaN); //false

isNaN()函數用來判斷參數不是一個數,該函數還將會把參數嘗試著轉成數值,再去判斷

    alert(isNaN(NaN));      //true
    alert(isNaN(10));       //false 10
    alert(isNaN("10"));     //false 10
    alert(isNaN("blue"));   //true
    alert(isNaN(true));     //false 1

9.break continue

    break語句會立即退出循環,強制執行循環以后的語句。
    continue語句雖然也是退出循環,但退出循環后,會退出循環從循環的頂部繼續執行
    //break
    var num = 0;
    for (var i=1; i < 10; i++) {
        if (i % 5 == 0) {
            break;
        }
            num++;
    }
    console.log(num);    //4
    
    //containue
    var num = 0;
    for (var i=1; i < 10; i++) {
        if (i % 5 == 0) {
            continue;
            }
        };
    console.log(num);   //8

10.基本數據類型引用數據類型

        1.在js中分為基本數據類型和引用數據類型
        
        2.基本數據類型保存那些基本數據片段,而引用數據類型中保存著對堆內存中對象的引用,是一個指針。與其他語言的不同是,你不可以直接訪問堆內存空間中的位置和操作堆內存空間。只能操作對象在棧內存中的引用地址。
        
        3.引用類型數據在棧內存中保存的實際上是對象在堆內存中的引用地址。通過這個引用地址可以快速查找到保存中堆內存中的對象。
        
        4.在將一個保存著基本數據類型的變量復制給另一個變量時,會將原始值的副本賦值給新變量,此后這兩個變量是完全獨立的,他們只是擁有相同的value而已。
        
       5.在將一個保存著對象內存地址的變量復制給另一個變量時,會把這個內存地址賦值給新變量,也就是說這兩個變量都指向了堆內存中的同一個對象,他們中任何一個作出的改變都會反映在另一個身上。(這里要理解的一點就是,復制對象時并不會在堆內存中新生成一個一模一樣的對象,只是多了一個保存指向這個對象指針的變量罷了)。多了一個指針。
      
       6.可以為引用數據類型值添加屬性和方法,不可以為基本數據類型值添加屬性和方法。
      資料鏈接:[資料鏈接](http://www.cnblogs.com/cxying93/p/6106469.html)
      

11.typeof instanceof

    `typeof`能夠辨別基本數據類型,卻無法辨別引用數據類型,只能判斷出來是對象,而無法判定是什么類型的對象。
    `instanceof`可以判斷一個引用數據類型是什么類型的對象。

12.執行環境

        執行環境定義了變量或者函數有權訪問的的其他數據,每個執行環境都有一個與之關聯的變量對象。環境中定義的的所有變量和函數都保存在這個對象中。我們編寫代碼時,無法去操控這個對象,但解析器在處理數據時,會在后臺使用他們。
        全局執行環境被認為是window對象,因為所有的全局變量和函數都是被當作屬性和方法創建的。
        某個執行環境中的所有代碼執行完畢后,該環境中的所有變量和函數定義也將被銷毀。
        每個函數都有自己的執行環境,當執行流進入一個函數時,函數的環境就被推入一個環境棧中,當函數執行完畢之后,棧將起環境推出,把控制權返回給之前的執行環境。ECMAscript程序的執行流正是由這個機制控制著。
        函數在處于執行流時,會沿著作用域鏈去尋找變量,作用域鏈的前端始終是當前執行代碼所在環境的變量對象下一個變量來自外部環境,再下一個來自下一個包含環境。一層一層往外尋找,當找到第一個符合變量時,不在繼續尋找,當沒有找到時,會報錯。

13.垃圾回收機制

    javascript具有垃圾回收機制,執行環境會管理代碼執行過程中的內存使用。
    原理:找到那些不在繼續使用的變量,然后釋放其內存。
    方式:1.標記清除
    這是javascript中最常用的垃圾回收方式。當變量進入執行環境是,就標記這個變量為“進入環境”。從邏輯上講,永遠不能釋放進入環境的變量所占用的內存,因為只要執行流進入相應的環境,就可能會用到他們。當變量離開環境時,則將其標記為“離開環境”。
  垃圾收集器在運行的時候會給存儲在內存中的所有變量都加上標記。然后,它會去掉環境中的變量以及被環境中的變量引用的標記。而在此之后再被加上標記的變量將被視為準備刪除的變量,原因是環境中的變量已經無法訪問到這些變量了。最后。垃圾收集器完成內存清除工作,銷毀那些帶標記的值,并回收他們所占用的內存空間。
      
      2.引用計數
      另一種不太常見的垃圾回收策略是引用計數。引用計數的含義是跟蹤記錄每個值被引用的次數。當聲明了一個變量并將一個引用類型賦值給該變量時,則這個值的引用次數就是1。相反,如果包含對這個值引用的變量又取得了另外一個值,則這個值的引用次數就減1。當這個引用次數變成0時,則說明沒有辦法再訪問這個值了,因而就可以將其所占的內存空間給收回來。這樣,垃圾收集器下次再運行時,它就會釋放那些引用次數為0的值所占的內存。

14.Array.prototype

    數組對象的方法,都是通過繼承構造函數Array的原型對象方法而來的。可以在瀏覽器查看window.Array.prototype
    
一:數組插入和移除數組元素

    1.push()
    從數組的末尾插入任意多的元素,返回值為新數組長度。
    var colors = new Array();
    var count = colors.push("red", "green"); 
    console.log(count); //2
    
    2.pop()
    從數組末尾移除一項,返回值為被移除的項。
    var name = ["tom","jack","tony"];
    var result = name.pop();
    console.log(result);//"tony"
    
    3.shift()
    移除數組的第一項,返回值為被移除的項。和pop對立!
    var name = ["tom","jack","tony"];
    var result = name.shift();
    console.log(result);//"tom"
    
    4.unshift()
    從數組的開頭插入任意多的元素,返回值為新數組長度。和push()對立!
    var colors = ["javascript","css","html"];
    var count = colors.unshift("jquery", "vue"); 
    console.log(count); //5
    
二:數組排序
    
    1.sort(function)
    sort排序并不會按照我們的意愿去排列數組,如果調用該方法時沒有使用參數,將按字母順序對數組中的元素進行排序,說得更精確點,是按照字符編碼的順序進行排序。要實現這一點,首先應把數組的元素都轉換成字符串toString(),以便進行比較。
    
    要想按照我們人為的意愿,對數值數組進行排序:
    可使用:arrayObj.sort(function(a,b){
        return a-b;
    })
    2.reverse()
    reverse會把數組中的元素顛倒過來。
三:數組截取
    
    1.slice(a,b)
    slice為數組截取,有兩個參數,即是返回項的起始和結束位置。當只有一個參數時,會從當前數組項截取到數組末尾。當兩個參數時,返回起始和結束項位置的元素,但是不包括結束位置的項。slice方法不影響原始數組。
    2.splice(a,b,c)
    1.刪除-用于刪除元素,兩個參數,第一個參數(要刪除第一項的位置),第二個參數(要刪除的項數)
    2.插入-向數組指定位置插入任意項元素。三個參數,第一個參數(插入位置),第二個參數(0),第三個參數(插入的項)
    3.替換-向數組指定位置插入任意項元素,同時刪除任意數量的項,三個參數。第一個參數(起始位置),第二個參數(刪除的項數),第三個參數(插入任意數量的項)
    
四:位置方法
    indexOf/lastIndexOf
    分別為從數組的第一個元素和數組的最后一個元素查找特定項,返回值為查找的項在數組中的位置。
    var numbers = [1,2,3,4,5,4,3,2,1];
    console.log(numbers.indexOf(4));        //3
    console.log(numbers.lastIndexOf(4));    //5
    
五:迭代方法
    
        1、every(): 對數組中的每一項運行給定的函數,如果該函數對每一項都返回true,則結果返回true。
        2、filter(): 對數組中的每一項運行給定函數,返回該函數會返回true的項組成的數組。
        3、forEach(): 對數組中的每一項運行給定函數,這個方法沒有返回值。
        4、map(): 對數組中的每一項運行給定函數,返回每次函數調用的結果組成的數組。
        5、some(): 對數組中的每一項運行給定函數,如果該函數任意一項返回true,則返回true。
    var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
    
    //every,每一項是否都滿足
    var everyResult = numbers.every(function(item, index, array) {
        return (item > 2);
    });
    
    //some,是否有一些滿足
    var someResult = numbers.some(function(item) {
        return (item > 2);
    });
    
    console.log(everyResult);      //false
    console.log(someResult);        //true
    
    //filter,找到符合條件的項
    var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
    var filterResult = numbers.filter(function(item) {
        return (item > 2);
    });
    
    console.log(filterResult);  \\[3, 4, 5, 4, 3]
    
    //map,就是對數組中的每一項執行操作,再返回數組
    var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
    var mapResult = numbers.map(function(item) {
        return (item * 2);
    });

    console.log(mapResult);     //[2, 4, 6, 8, 10, 8, 6, 4, 2]
    
    //forEach和for循環差不多,一般是用來循環數組元素,做一些操作
    var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
    numbers.forEach(function(item, index, arr) {
        //這里執行一些操作
    });

六:并歸
    reduce()/reduceRight()
    很多時候需要累加數組項的得到一個值(比如說求和)。之前都是用for循環,會很out...
    reduce()方法接收一個函數callbackfn作為累加器(accumulator),數組中的每個值(從左到右)開始合并,最終為一個值。第二個參數可選,即是人為的插入并歸起始項。
    var arr = [0,1,2,3,4]; 
    
    arr.reduce(function (preValue,curValue,index,array) {
        return preValue + curValue; 
    }); //10
    
    reduceRight()方法和reduce方法雷同,只不過從右邊并歸開始。

16.元素寬高和位置

  • 頁面適口大小(即我們看見的頁面)
   var pageWidth = window.innerWidth,//頁面適口寬度
       pageHeight = window.innerHeight;//頁面適口高度
   if (typeof pageWidth != "number"){
       if (document.compatMode == "CSS1Compat"){
           pageWidth = document.documentElement.clientWidth;
           pageHeight = document.documentElement.clientHeight;
       } else {
           pageWidth = document.body.clientWidth;
           pageHeight = document.body.clientHeight;
 
  • 窗口位置

   var leftPos = (typeof window.screenLeft == "number") ?
                 window.screenLeft : window.screenX;//窗口距左
   var topPos = (typeof window.screenTop == "number") ?
                 window.screenTop : window.screenY;//窗口距右
  • 元素
    原生js中:
    offsetHeight/offsetWidth:帶邊框高/寬
    clientHeight/offsetWidth:不帶邊框高/寬
    offsetTop/offsetLeft:相對視窗的上邊/左邊
    
    jQuery中:
    $(".box").offset().top/.left:相對視窗的上邊/左邊(和上面原生js一樣)
    $(".box").position().top/.left:相對父元素的上邊/左邊
    
    $(".box").height(num)/width(num):獲取/設置一個元素的寬高(不包括邊框和padding)
    
    $(".box").innerHeight()/innerWidth():獲取一個元素的寬高(包含padding)
    
    $(".box").outerHeight()/outerWidth():獲取一個元素的寬高(包含padding和border)
    

  • 事件對象獲取目標元素坐標值
    $(".box").click(function(e){
        e.pageX/pageY:指的是觸發事件距離于頁面左邊和頂端的距離
        e.clientX/clientY:指的是觸發事件距離于適口左邊和頂端的距離
        e.offsetX/offsetY:指的是觸發事件距離于觸發目標左邊和頂端的距離
        e.screenX/screenY:指的是觸發事件距離于屏幕左邊和頂端的距離
    })

11.直客通-gitlab圖片

zkt-count.gif
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,397評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,347評論 2 377

推薦閱讀更多精彩內容