萬字圖解JavaScript筆記總結

2022-07-21 18:00:57
本篇文章給大家帶來了關於的相關知識,其中主要整理了筆記總結的相關問題,包括了建構函式、原型物件 prototype、物件原型等等內容,下面一起來看一下,希望對大家有幫助。

【相關推薦:、】

變數

  • 一個變數只定義但沒有賦初值,預設值是 undefined
  • 定義變數時必須寫var(不用var定義,而直接將值賦給它,隨不引發報錯,但會產生作用域問題)
變數宣告的提升
  • 你可以提前使用一個稍後才宣告的變數,而不會引發異常
  • 再執行所有程式碼前,js有預解析階段,會預讀所有變數的定義
  • 注意:變數宣告提升只提升定義不提升值
console.log(a);   // 先使用變數var a = 12;     // 後定義變數
資料型別
  • 基本資料型別

    • Number

      • 所有數位部分大小、不分整浮、不分正負,都是數位型別
      • 較大或較小數(絕對值較小)可以寫成科學計數法3e8就是3^8
      • 二進位制數值以0b開頭,八進位制以0開頭,十六進位制以0x開頭
      • NaN,not a number,即「不是一個數」,但它是一個數位型別的值(數學運算中,若結果不能得到數位,結果往往都是NaN,NaN == NaN結果為false)
      • Infinity無窮大或無窮小
    • String

      • 字串常用方法
      方法功能
      charAt()得到指定位置字元(越界為空串)
      substring()提取子串
      substr()提取字串
      slice()提取子串
      toUpperCase()將字串變為大寫
      toLowerCase()將字串變為小寫
      indexOf()檢索字串(模式匹配)
      • substring(a, b) 從a開始到b結束的子串,不包括b處;如果省略第二個引數,返回的子串會一直到字串的結尾,若a > b,會自動調整為小數在前
      • substr(a, b) 從a開始長度為b的子串;如果省略第二個引數,返回的子串會一直到字串的結尾;a可以是負數,表示倒數位置
      • slice(a, b) 從a開始到b結束的子串,不包括b處;兩個引數都可以是負數;a必須小於b,否則沒有結果(空串)
    • Boolean

    • Undefined

      • undefined既是值又是一種型別,這種型別只有它自己一個值
    • Null

      • 當我們需要將物件銷燬、陣列銷燬或者刪除事件監聽時、通常將他們設定為null
  • 複雜資料型別

    • Object
    • Array
    • Function
    • RegExp
    • Date
    • Map
    • Set
    • ……
Typeof運運算元

可以用來檢測值或變數的型別

typeof 5;          // numbertypeof 'niubi';   // string
型別名typeof 檢測結果值舉例
數位型別number5
字串型別string‘niubi’
布林型別booleantrue
undefinedundefinedundefined
null型別objectnull
資料型別轉換

使用**Number()**函數

// 字串 --> 數位Number('123');        // 123Number('123.4');      // 123.4Number('123年');       // NaNNumber('2e3');         // 2000Number('');            // 0Number('1 + 1');       // NaN// 布林值 --> 數位Number(true);         // 1Number(false);        // 0// undefined 和 null --> 數位Number(undefined);    // NaNNumber(null);         // 0

**parseInt()**函數將字串轉為整數

將自動截掉第一個非數位字元之後的所有字元

parseInt('3.14');       // 3parseInt('3.14是圓周率');   // 3parseInt('圓周率是3.14');    // NaNparseInt('3.99');           // 3

**parseFloat()**函數將字串轉為浮點數

自動截掉第一個非數位字元、非小數點之後的所有字元

parseFloat('3.14');         // 3.14parseFloat('3.14是圓周率');   // 3.14parseFloat('圓周率是3.14');   // NaNparseFloat('3.99');          // 3.99// 會自動將true和false轉為字串,結果為NaN

**String()**函數

變成「長得相同」的字串。科學計數法和非10進位制數位會轉為10進位制的值

String(123);       // '123'String(123.4);     // '123.4'String(2e3);       // '2000'String(NaN);       // 'NaN'String(Infinity);  // 'Infinity'String(0xf);       // '15'String(true);      // 'true'String(false);     // 'false'String(undefined);   // 'undefined'String(null);        // 'null'

**Boolean()**函數

// 數位 --> 布林值    0和NaN轉為false,其他轉為trueBoolean(123);    // trueBoolean(0);      // falseBoolean(NaN);    // falseBoolean(Infinity);    // trueBoolean(-Infinity);    // true// 布林值 --> 布林值     空串轉為false,其他轉為true;Boolean('');     // falseBoolean('abc');    // trueBoolean('false');  // true// undefined 和 null --> 布林值      轉為falseBoolean(undefined);      // falseBoolean(null);           // false

**prompt()**函數函數彈出輸入框

var num = prompt('請輸入第一個數位');    // 返回值為string

表示式與運運算元

隱式型別轉換

如果參與數學運算的某運算元不是數位型,那麼JavaScript會自動將此運算元轉換位數位型

隱式轉換的本質是內部呼叫Number()函數

3 * '4' 	 // 12true + true    // 2false + 2     // 23 * '2天'     // NaN
toFixed(a)方法保留a位小數
Math.pow(2, 3)      // 2^3Math.sqrt(81)      // 9Math.ceil()        // 向上取整Math.floor()       // 向下取整
關係運算子
===     // 全等於!==     // 不全等於// 兩個等號 == 運運算元不比較值的型別,它會進行隱式轉換後比較值是否相等1 == true      // true1===true       // false0 == false     // true0 === false    // false0 == undefined  // false0 === undefined   // falseundefined == null  // trueundefined === null    // false

**isNaN()**函數判斷變數值是否為NaN

但isNaN()也不好用,它的機理是:只要該變數傳入Number()的執行結果是NaN,則isNaN()函數都會得到true

短路求值

a && b a真,值為b;a假,值為a

a||b a真,值為a,a假,值為b

邏輯運算優先順序:非 --> 與 --> 或

綜合運算運算順序:非 --> 數學運算 --> 關係運算 --> 邏輯運算

流程控制語句

亂數函數Math.random()

得到[a, b]區間的整數,公式為 parseInt(Math.random() * (b - a + 1)) + a;

陣列

var arr = ['A', 'B', 'C', 'D']; var arr = new Array('A', 'B', 'C', 'D');var arr = new Array(4);     長度為4的陣列,每一項都是undefined

下標存取越界時返回undefined

var arr = [2, 6, 7, 3];arr[6] = 4;console.log(arr);此時下標越界,不會報錯,而是會將陣列擴充套件,下標6處為4,中間為empty

Array.isArray()方法可以用來檢測陣列

函數

函數定義

// 常規function fun() {
    // 函數體語句}// 匿名函數var fun = function () {
    // 函數體語句}

函數宣告的提升

fun();function fun() {    // 在預解析階段會被提升
    alert("函數被執行");}// 如果函數時用函數表示式的寫法定義的,則沒有提升特性fun();     // 引發錯誤var fun = function () {
    alert("函數被執行");}

函數優先提升

// 函數優先提升// 函數表示式後提升; 變數宣告提升,無法覆蓋提升的函數fun();    // 彈出Bvar fun = function () {
    alert('A');}function fun() {
    alert('B');}fun();     // 彈出A

實參與形參個數不同

  1. 實參個數多於形參,沒有形參接收它
  2. 實參個數少於形參,沒有接收到實參的形參值為undefined

arguments 類陣列物件

  1. 函數內arguments表示它接收到的實參列表,它是一個類陣列物件
  2. 類陣列物件:所有屬性均從0開始的自然數序列,並且有length屬性,和陣列類似可以用方括號書寫下標存取物件的某個屬性值,但不能呼叫陣列的方法

var宣告與省略

在函數外,用var宣告的變數為全域性變數,不用var宣告的變數為全域性變數

在函數中,用var宣告的變數為區域性變數,不用var宣告的變數為全域性變數

同為全域性變數,同為window物件的其中一個屬性,用var宣告的變數不可以刪除,不用var宣告的變數可以刪除!

返回值

function sum(a, b) {
    return a + b;}var result = sum(3, 5);    // 返回值可被變數接收

若函數沒有返回值,則對它列印的結果是undefined

sort(a, b)方法

這個函數中的a、b分別表示陣列中靠前和靠後的項,如果需要將它們交換位置,則返回任意正數;否則就返回負數

var arr = [33, 22, 11, 55];arr.sort(function (a, b) {
    if (a > b) {
        return 1;
    }
    return -1;});

變數賦值


舉例當var a = b變數傳值時當用 == 比較時
基本型別值數位型、字串型、布林型、undefined型記憶體中產生新的副本比較值是否相等
參照型別值物件、陣列記憶體中不產生新的副本,而是讓新變數指向同一個物件比較記憶體地址是否相同,即比較是否是同一個物件

陣列深度克隆

var arr1 = [1, 2, 3, [4, 5]];function deepClone(arr) {
    var result = [];
    for (var i = 0; i < arr.length; i++) {
        if (Array.isArray(arr[i])) {
            result.push(deepClone(arr[i]));
        } else {
            result.push(arr[i]);
        }
    }
    return result;}

區域性函數

定義在一個函數內部的函數是區域性函數

只能在函數內部呼叫

function fun() {
    function inner() {
        console.log('你好');
    }
    inner();   // 呼叫inner函數}fun();

作用域鏈

在函數巢狀中,變數會從內到外逐層尋找它的定義

var a = 10;var b = 20;function fun() {
    var c = 30;
    function inner() {
        var a = 40;
        var d = 50;
        console.log(a, b, c, d);   // 使用變數時,js會從當前層開始,逐層向外尋找定義
    }
    inner();}fun();

閉包

閉包是函數本身和該函數宣告時所處的環境狀態的組合

函數能夠」記憶住「其定義時所處的環境,即使函數不在其定義的環境中被呼叫,也能存取定義時所處環境的變數

在js中,每次建立函數時都會建立閉包,但是閉包特性往往需要將函數」換一個地方「執行,才能被觀察出來

閉包的功能:

  1. 記憶性:當閉包產生時,函數所處環境的狀態會始終保持在記憶體中,不會在外層函數呼叫後被自動清除。

    function fun() {
        var name = 'niubi';
        function innerFun() {
            alert(name);
        }
        return innerFun;}var inn = fun();inn();     // 內部函數被移動到了外部執行
  2. 模擬私有變數

    function fun() {
        var a = 0;
        return function() {
            alert(a);
        }}var getA = fun();getA();
function fun() {
    var a = 0;
    return {
        getA: function () {
            return a;
        },
        add: function () {
            a++;
        }, 
        pow: function () {
            a *= 2;
        }
    };}var obj = fun();console.log(obj.getA());obj.add();

注意:不能濫用閉包,否則會造成網頁的效能問題,嚴重時可能導致記憶體漏失。

立即呼叫函數IIFE

特殊寫法,一旦被定義,就立即被呼叫

函數必須轉為函數表示式才能被呼叫

(function () {       // 通過圓括號將函數變為表示式
    // statements})();+function() {
    alert(1);}();-function() {
    alert(1);}();
  1. 可以用來給變數賦值

    var age = 12;var sex = '男';var title = (function () {
        if (age < 18) {
            return '小朋友';
        } else {
            if (sex == '男') {
                return '先生';
            } else {
                return '女士';
            }
        }})();
  2. 在一些場合(如for迴圈中)將全域性變數變為區域性變數,語法更緊湊

var arr = [];for (var i = 0; i < 5; i++) {
    arr.push(function () {
        alert(i);     
    });}arr[2]();    // 彈出5

解決方法:

var arr = [];for (var i = 0; i < 5; i++) {
    (function (i)  {
        arr.push(function() {
            alert(i);
        });
    })(i);}arr[2]();   // 彈出2

DOM

nodeType常用屬性值

節點的nodeType屬性可以顯示這個節點具體的型別

nodeType值節點型別
1元素節點,例如

3文位元組點
8註釋節點
9document節點
10DTD節點

document物件

存取元素節點主要依靠document物件

幾乎所有DOM的功能都被封裝到了document物件中

document物件也表示整個HTML檔案,它是DOM節點樹的根

存取元素節點的常用方法

方法功能
document.getElementById()通過id得到元素
document.getElementsByTagName()通過標籤名得到元素陣列
document.getElementsByClassName()通過類名得到元素陣列
document.querySelector()通過選擇器得到元素
document.querySelectorAll()通過選擇器得到元素陣列

document.getElementById()

如果頁面上有相同id的元素,則只能得到第一個

<p id = "box">我是一個盒子</p><p id = "para">我是一個段落</p>
var box = document.getElementById('box');var para = document.getElementById('para');

getElementsByTagName()

陣列方便遍歷,從而可以批次操控元素節點

即使頁面上只有一個指定標籤名的節點,也將得到長度為1的陣列

任何一個節點元素也可以呼叫getElementsByTagName()方法,從而的到其內部的某種類的元素節點

<p>段落</p><p>段落</p><p>段落</p><p>段落</p>
var ps = document.getElementsByTagName('p');

getElementsByClassName()

<p class = "spec">盒子</p><p class = "spec">盒子</p><p class = "spec">盒子</p><p class = "spec">盒子</p>
var spec_ps = document.getElementsByClassName('spec');

querySelector()

該方法只能得到頁面上一個元素,如果有多個元素符合條件,則只能得到第一個元素

<p id = "box1">
    <p>段落</p>
    <p class = "spec">段落</p>
    <p>段落</p>
    <p>段落</p></p>
var the_p = document.querySelector('#box1 .spec');

querySelectAll()

即使頁面上只有一個符合選擇器的節點,也將得到長度為1的陣列

延遲執行

使用window.onload = function() {}事件(給window物件新增事件監聽,onload表示頁面都載入完畢了),使頁面載入完畢後,再執行指定的程式碼

節點的關係

關係考慮所有節點只考慮元素節點
子節點childNodeschildren
父節點parentNode
第一個子節點firstChildfirstElementChild
最後一個子節點lastChildlastElementChild
前一個兄弟節點previousSiblingpreviousElementSibling
後一個兄弟節點nextSiblingnextElementSibling

注意:文位元組點也屬於節點,所以我們一般情況下會排除文位元組點的干擾(用只考慮元素節點)

書寫常見節點關係函數

<body>
    <p id = "box1">
        <p>段落</p>
        <p class = "spec">段落</p>
        <p>段落</p>
        <p>段落</p>
	</p>
    <script>
        var box = document.getElementById('box1');
        var spec = document.getElementsByClassName('spec');
        // 封裝一個函數,返回元素的所有子元素節點,類似children的功能
        function getChildren(node) {
            var children = [];
            // 遍歷node這個節點的所有子節點,判斷每一個位元組的nodeType屬性是不是1
            // 如果是1, 就推入結果陣列
            for (var i = 0; i < node.childNodes.length; i++) {
                if (node.childNodes[i] == 1) {
                    children.push(node.childNodes[i]);
                }
            }
            return children;
        }
       
        // 封裝一個函數,這個函數可以返回元素的前一個元素兄弟節點,類似previousElementSibling的功能
        function getElementPrevSibling(node) {
            var o = node;
            while (o.previousSibling != null) {
                if (o.prebiousSibling.nodeType == 1) {
                    // 結束迴圈,找到了
                    return o.previousSibling;
                }
                o = o.previousSibling;
            }
            return null;
        }
        
        // 封裝一個函數,該函數可以返回元素的所有元素兄弟節點
        function getAllElementSibling(node) {
            var prevs = [];
            var nexts = [];
            var o = node;
            while (o.previousSibling != null) {
                if (o.previousSibling.nodeType == 1) {
                    prevs.unshift(o.previousSibling);
                }
                o = o.previousSibling;
            }
            o = node;
            while (o.nextSibling != null) {
                if (o.nextSibling.nodeType == 1) {
                    nexts.push(o.nextSibling);
                }
                o = o.nextSibling;
            }
            return prevs.concat(nexts);
        }
    </script></body>

改變元素節點中的內容

改變元素節點中的內容可以使用兩個相關屬性

  • innerHTML

    能以HTML語法設定節點中的內容

  • innerText

    只能以純文字的形式設定節點中的內容

<body>
    <p id = "box"></p>
    <script>
        var oBox = document.getElementById('box');
        oBox.innerHTML = '<ul><li>牛奶</li><li>咖啡</li></ul>';    // 可以解析HTML語法
        // oBox.innerText = 'niub';    // 裡面只能是純文字
    </script></body>

改變元素節點的CSS樣式

相當於在設定行內style屬性

oBox.style.backgroundColor = 'red';     // CSS 屬性要寫成駝峰形式oBox.style.backgroundImage = 'url(images/1.jpg)';oBox.style.fontSize = '32px';

改變元素節點的HTML屬性

標準的W3C屬性,如src、href等,只需直接打點進行更改即可

oImg.src = 'images/2.jpg';

不符合W3C標準的屬性,要使用setAttribute()和getAttribute()來設定、讀取

<body>
    <p id = "box"></p>
    <script>
        var box = document.getElementById('box');
        box.setAttribute('data-n', 10);    // 新增data-n屬性,值為10
        var n = box.getAttribute('date-n');
        alert(n);
    </script></body>

節點的建立

document.createElement()方法用於建立一個指定tagname的HTML元素

var op = document.createElement('p');

新建立出的節點是」孤兒節點「,並沒有被掛載到DOM樹上,無法看見他

必須繼續使用appendChild() 或 insertBefore() 方法將孤兒節點插入到DOM樹上

任何已經在DOM樹上的節點,都可以呼叫appendChild() 方法,它可以將孤兒節點掛載到他的內部,成為它的最後一個子節點

父節點.appendChild(孤兒節點);

任何已經在DOM樹上的節點,都可以呼叫insertBefore() 方法,它可以將孤兒節點掛載到它的內部,成為它的」標杆子節點「之前的節點

父節點.insertBefore(孤兒節點, 標杆節點);

移動節點

如果將已經掛載到DOM樹上的節點成為appendChild()或者insertBefore()的引數,這個節點將會被移動

新父節點.appendChild(已經有父親的節點);新父節點.insertBefore(已經有父親的節點, 標杆子節點);// 這意味著一個節點不能同時位於DOM樹的兩個位置

刪除節點

removeChild() 方法從DOM中刪除一個子節點

父節點.removeChild(要刪除子節點);

克隆節點

cloneNode()方法可以克隆節點,克隆出的節點是」孤兒節點「

引數是boolean型別,表示是否採用深度克隆,若為true,則該節點的所有後代節點也都會被克隆,若為false,則只克隆該節點本身

var 孤兒節點 = 老節點.cloneNode();var 孤兒節點 = 老節點.cloneNode(true);

事件

  • 常見的滑鼠事件監聽
事件名事件描述
onclick當滑鼠單機某個物件
ondbclick當滑鼠雙擊某個物件
onmousedown當某個滑鼠按鍵在某個物件上被按下
onmouseup當某個滑鼠按鍵在某個物件上被鬆開
onmousemove當某個滑鼠按鍵在某個物件上被移動
onmouseenter當滑鼠進入某個物件(相似事件onmouseover)
onmouseleave當滑鼠離開某個物件(相似事件onmouseout)

onmouseenter不冒泡,onmouseover冒泡

  • 常見的鍵盤事件監聽
事件名事件描述
onkeypress當某個鍵盤的鍵被按下(系統按鈕如箭頭鍵和功能鍵無法得到識別)
onkeydown當某個鍵盤的鍵被按下(系統按鈕可是識別,並且會優先於onkeypress發生)
onkeyup當某個鍵盤的鍵被鬆開
  • 常見的表單事件監聽
事件名事件描述
onchange使用者改變域的內容之後
oninput正在修改域的內容(輸入內容)
onfocus當某元素獲得焦點(比如tab鍵或滑鼠點選)
onblur當某元素失去焦點
onsubmit當表單被提交
onreset當表單被重置
  • 常見的頁面事件監聽
事件名事件描述
onload當頁面或影象被完成載入
onunload當使用者退出頁面

當盒子巢狀時事件監聽的執行順序

<p id = "box1">
    <p id = "box2">
        <p id = "box3"></p>
    </p></p><script>
    var oBox1 = document.getElementById('box1');
    var oBox2 = document.getElementById('box2');
    var oBox3 = document.getElementById('box3');
    
    oBox1.onclick = function () {
        console.log('box1');
    };
    
    oBox2.onclick = function () {
        console.log('box2');
    };
    
    oBox3.onclick = function () {
        console.log('box3');
    };
    // 點選最裡面的盒子,傳播方向是從內到外</script>

事件傳播

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-XflsWv91-1656640428428)(images/image-20220430211035636.png)]

事件的傳播是:先從外到內,然後再從內到外(最內層不是先捕獲再冒泡,而是根據書寫程式碼順序決定。同名盒子同階段與順序有關。如果給元素設定相同的兩個或多個同名事件,則DOM0級寫法後面寫的會覆蓋先寫的;而DOM2級會按順序執行)

onxxxx(DOM0級事件監聽)只能監聽冒泡階段,所以觀察出來的結果是從內到外

addEventListener()方法(DOM2級事件監聽)

oBox.addEventListener('click',function() {
 // 這裡是事件處理常式}, true);     // 第三個引數若為true,監聽捕獲階段,為false,監聽冒泡階段

事件物件

事件處理常式提供一個形式引數,它是一個物件,封裝了本次事件的細節

這個引數通常用單詞event或字母e來表示

oBox.onmousemove = function (e) {
 // 物件e就是這次事件的「事件物件」};

物件相關屬性

  • 滑鼠位置相關屬性

觸發這次事件時滑鼠的位置的屬性

屬性屬性描述
clientX滑鼠指標相對於瀏覽器的水平座標
clientY滑鼠指標相對於瀏覽器的垂直座標
pageX滑鼠指標相對於整張網頁的水平座標
pageY滑鼠指標相對於整張網頁的垂直座標
offsetX滑鼠指標相對於事件源元素的水平座標
offsetY滑鼠指標相對於事件源元素的垂直座標
  • e.charCode和e.keyCode屬性

e.charCode屬性通常用於onkeypress事件中,表示使用者輸入的字元的「字元碼」

字元字元碼
數位0 ~ 數位948 ~ 57
大寫字母A ~ Z65 ~ 90
小寫字母 a ~ z97 ~ 122

e.keyCode屬性通常用於onkeydown和onkeyup事件中,表示使用者按下的按鍵的「鍵碼」

按鍵鍵碼
數位0 ~ 數位948 ~ 57
字母部分大小寫 a ~ z65 ~ 90
四個方向鍵 ← ↑ → ↓37、38、39、40
確認鍵13
空格鍵32

阻止預設事件

e.preventDefault()方法用來阻止事件產生的「預設動作」

e.stopPropagation()方法用來阻止事件繼續傳播

批次新增事件監聽效能問題

  • 每一個事件監聽註冊都會消耗一定的系統記憶體,而批次新增事件會導致監聽數量太多,記憶體消耗會很大

事件委託

每一個事件監聽註冊都會消耗一定的系統記憶體,而批次新增事件會導致監聽數量太多,記憶體消耗會很大(當有大量類似元素需要批次新增事件監聽時,使用事件委託可以減少記憶體開銷)

利用事件冒泡機制,將後代元素事件委託給祖先元素

注意:不能委託不冒泡的事件給祖先元素

當有動態元素節點上樹時,使用事件委託可以讓新上樹的元素具有事件監聽

相關屬性

屬性屬性描述
target觸發此事件的最早元素,即」事件源元素「
currentTarget事件處理程式附加到的元素(this)

定時器

setInterval()函數可以重複呼叫一個函數,在每次呼叫之間具有固定的時間間隔

setInterval(function () {
    // 這個函數將自動被以固定間隔時間呼叫}, 2000);    // 第二個引數為間隔時間,單位為毫秒// 該函數可以接收第3、4……個引數,他們將按順序傳入函數setInterval(function (a, b) {
    // 形式引數 a 的值是88,形參b的值是66}, 2000, 88, 66);     // 從第三個引數開始,表示傳入函數內的引數// 具名函數也可以傳入setIntervalvar a = 0;function fun() {
    console.log(++a);};setInterval(fun, 1000);

清除定時器

clearInterval() 函數可以清除一個定時器

// 設定定時器,並用timer變數接收這個定時器var timer = setInterval(function () {
    }, 2000);// 點選按鈕時,清除定時器oBtn.onclick = function () {
    clearInterval(timer);    };

延時器

setTimeout() 函數可以設定一個延時器,當指定時間到了之後,會執行函數一次,不再重複執行

var timer = setTimeout(function () {
    // 這個函數會在 2 秒後執行一次}, 2000);clearTimeout(timer);    // 清除延時器

非同步

非同步: 不會阻塞CPU繼續執行其他語句,當非同步完成時,會執行 」回撥函數「(callback)

setInterval() 和 setTimeout() 是兩個非同步語句

setTimeout(function () {
    console.log('A');}, 2000);  // 非同步語句console.log('B');    // 非同步語句不會阻塞程式的正常執行// 執行結果BA

函數節流

一個函數執行一次後,只有大於設定的執行週期後才允許執行第二次

var lock = true;function 需要節流的函數() {
    // 如果鎖時關閉狀態,則不執行
    if(!lock) return;
    // 函數核心語句
    
    // 關鎖
    lock = false;
    
    // 指定毫秒數後將鎖開啟
    setTimeout(function () {
        lock = true;
    }, 2000);}

BOM

BOM(Browser Object Model,瀏覽器物件模型)是JS與瀏覽器視窗互動的介面

window物件

window物件是當前 js 指令碼執行所處的視窗,而這個視窗中包含DOM結構,window.document屬性就是document物件

在有分頁功能的瀏覽器中,每個標籤都擁有自己的window物件;也就是說,同一個視窗的分頁之間不會共用一個window物件

  1. 全域性變數會成為window物件的屬性

    var a = 10;console.log(window.a == a);   // true

    這意味著多個js檔案之間是共用全域性作用域的,即js檔案沒有作用域隔離功能

  2. 內建函數普遍是window的方法

    如setInterval()、alert()等內建函數,普遍是window的方法

視窗尺寸相關屬性

屬性意義
innerHeight瀏覽器視窗的內容區域的高度,包含水平卷軸(如果有的話)
innerWidth瀏覽器視窗的內容區域的寬度,包含垂直卷軸(如果有的話)
outerHeight瀏覽器視窗的外部高度
outerWidth瀏覽器視窗的外部寬度

獲得不包含卷軸的視窗寬度,要用document.documentElement.clientWidth

resize事件

在視窗大小改變之後,就會觸發resize事件,可以使用window.onresize或者window.addEventListener(‘resize’)來繫結事件處理常式

已捲動高度

window.scrollY屬性表示在垂直方向已捲動的畫素值

document.documentElement.scrollTop屬性也表示視窗捲動高度

為了更好的瀏覽器相容行,通常將兩個一起寫

var scrollTop = window.scrollY || document.documentElement.scrollTop;

document.documentElement.scrollTop不是唯讀的,而window.scrollY是唯讀的

scroll事件

在視窗被捲動之後,就會觸發scroll事件,可以使用window.onscroll或者window.addEventListener(‘scroll’)來繫結事件處理常式

Navigator物件

window.navigator屬性可以檢索navigator物件,它內部含有使用者此次活動的瀏覽器的相關屬性和標識

屬性意義
appName瀏覽器官方名稱
appVersion瀏覽器版本
userAgent瀏覽器的使用者代理(含有核心資訊和封裝殼資訊)
platform使用者作業系統

History物件

window.history 物件提供了操作瀏覽器對談歷史的介面

常用的操作就是模擬瀏覽器回退按鈕

history.back();       // 等同於點選瀏覽器的回退按鈕history.go(-1);       // 等同於 history.back();

Location物件

window.location 標識當前所在網址,可以通過給這個屬性賦值命令瀏覽器進行頁面跳轉

window.location = 'http://www.baidu.com';window.location.href = 'http://www.baidu.com';
  • 重新載入當前頁面

    可以呼叫location的reload方法以重新載入當前頁面,引數true表示從伺服器強制載入

    window.location.reload(true);
  • GET 請求查詢引數

    window.location.search 屬性即為當前瀏覽器的 GET 請求查詢引數

offsetTops屬性

該屬性表示此元素到定位祖先元素的垂直距離

定位祖先元素:在祖先中,離自己最近的且擁有定位屬性的元素

使用這個屬性的時候,所有祖先元素不要有定位

物件導向

物件(object)是」鍵值對「的集合,表示屬性和值的對映關係

var obj = {
    name: '小明',
    age: 12,
    sex: '男',
    hobbies: ['足球', '程式設計']};     // js中 花括號表示物件

注意:

  • 如果物件的屬性鍵名不符合js識別符號命名規範,則這個鍵名必須用引號包裹

  • 如果屬性名不符合js識別符號命名規範,則必須用方括號的寫法來存取

  • 如果屬性名以變數形式儲存,則必須使用方括號形式

    var obj = {
        a: 1,
        b: 2,
        c: 3};var key = 'b';console.log(obj.key);    // undefinedconsole.log(obj[key]);   // 2

物件的建立

var obj = {
    a: 10};obj.b = 40;

刪除屬性

使用delete操作符刪除某個物件的屬性

var obj = {
    a: 1,
    b: 2};delete obj.a;

物件的方法

如果某個屬性值是函數,則它被稱為物件的方法

var xiaoming = {
    name: '小明',
    age: 12,
    sex: '男',
    hobbys: ['足球','游泳','程式設計'],
    'favorite-book': '舒克和貝塔',
    sayHello: function () {
        console.log('hello');
    }};

物件的遍歷

物件的遍歷需要使用for…in…迴圈,可是遍歷物件的每個鍵

for (var k in obj) {
    console.log('屬性' + k + '的值是' + obj[k]);}

物件的深克隆

var obj1 = {
    a: 1, 
    b: 2, 
    c: [33, 44, {
        m: 55,
        n: 66,
        p: [77, 88]
    }]};function DeepClone(o) {
    if (Array.isArray(o)) {
        var result = [];
        for (var i = 0; i < o.length; i++) {
            result.push(DeepClone(o[i]));
        }
    } else if(typeof o == 'object') {
        var result = {};
        for (var k in o) {
            result[k] = DeepClone(o[k]);
        }
    } else {
        var result = o;
    }
    return result;}

函數的上下文

函數中可以使用this關鍵字,它表示函數的上下文

同一個函數,用不同的形式呼叫它,則函數的上下文不同

函數只有被呼叫,他的上下文才能被確定

相關規則

規則上下文
物件.函數()物件
函數()window
陣列[下標]()陣列
IIFEwindow
定時器window
DOM事件處理常式繫結DOM的元素
call和apply任意指定
函數.call(上下文);函數.apply(上下文);

區別:

function sum(b1, b2) {
    alert(this.c + this.m + this.e + b1 + b2);}sum.call(xiaoming, 5, 3);    // call要用逗號羅列引數sum.apply(xiaoming, [5, 3]);  // apply要把引數寫到陣列中

new操作符呼叫函數

new 函數()

js規定,使用new操作符呼叫函數會進行「四步走」:

  1. 函數體內會自動建立出一個空白物件
  2. 函數的上下文(this)會指向這個物件
  3. 函數體內的語句會執行
  4. 函數會自動返回上下文物件,即使函數沒有return語句
function fun() {   // {}   this指向這個空物件
    this.a = 3;
    this.b = 5;    // {a: 3, b: 5}
    // 自動補充return this;}var obj = new fun();console.log(obj);

建構函式

將之前的函數進行一小步改進

function People(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;}var xiaoming = new People('小明', 12, '男');var xiaoming = new People('小紅', 10, '女');var xiaogang = new People('小剛', 13, '男');
  • 用new呼叫一個函數,這個函數就被稱為「建構函式」,任何函數都可以是建構函式,只需要用new呼叫它
  • 建構函式用來「構造新物件」,它內部的語句將為新物件新增若干屬性和方法,完成物件的初始化

為物件新增方法

function People(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.sayHello = function () {
        console.log('我是' + this.name);
    };}var xiaoming = new People('小明', 12, '男');xiaoming.sayHello();

prototype

任何函數都有prototype屬性,prototype是英語」原型「的意思,prototype屬性值是個物件,它預設擁有constructor屬性指回函數
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-hvEv1vmX-1656640428432)(images/image-20220512232708827.png)]

建構函式的prototype是範例的原型
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-9RrOcTvi-1656640428433)(images/image-20220512234215229.png)]

原型鏈查詢

範例可以打點存取它的原型的屬性和方法,這被成為」原型鏈查詢「

function People(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;}People.prototype.nationality = '中國';     // 在建構函式的prototype上新增nationality屬性var xiaoming = new People('小明', 12, '男');console.log(xiaoming.nationality);

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-5ncCeZjK-1656640428434)(images/image-20220512235017847.png)]

hasOwnProperty()

該方法可以檢查物件是否真正」自己擁有「某屬性或者方法

xiaoming.hasOwnProperty('name');    // truexiaoming.hasOwnProperty('age');     // truexiaoming.hasOwnProperty('sex');     // truexiaoming.hasOwnProperty('nationality');    // false

in

in運運算元只能檢查某個屬性或方法是否可以被物件存取,不能檢查是否是自己的屬性或方法

'name' in xiaoming     // true'age' in xiaoming      // true'sex' in xiaoming      // true'nationality' in xiaoming    // true

在prototype上新增方法

將方法直接新增到範例身上的缺點:每個範例和每個範例的方法函數都是記憶體中不同的函數,造成了記憶體的浪費,可以通過將方法寫道prototype上來解決。

function People(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;}People.prototype.sayHello = function () {
    console.log('我是' + this.name);};var xiaoming = new People('小明', 12, '男');xiaoming.sayHello();

原型鏈的終點

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-YMdNVRox-1656640428435)(images/image-20220514113830258.png)]

陣列的原型鏈

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-v6Kr9bIk-1656640428436)(images/Snipaste_2022-05-14_11-42-53.png)]

繼承

  1. 藉助原型鏈實現繼承

讓Student的prototype屬性指向父類別的範例,然後給Student的prototype新增Student的方法

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-yIhC3PN2-1656640428438)(images/Snipaste_2022-05-14_12-11-04.png)]

通過原型鏈實現繼承的問題

  • 如果父類別的屬性中有參照型別值,則這個屬性會被所有子類的範例共用
  • 子類別建構函式中,往往需要重複定義很多超類定義過的屬性。即,子類別建構函式寫的不夠優雅
  1. 藉助建構函式

為了解決原型中包含參照型別值所帶來問題和子類建構函式不優雅的問題,通常使用一種叫做 「藉助建構函式」 的技術,也被稱為 「偽造物件」 或 「經典繼承」

在子類建構函式的內部呼叫超類別建構函式,但要注意使用call()繫結上下文

function People(name, sex, age) {
    this.name = name;
    this.sex = sex;
    this.age = age;
    this.arr = [1, 2, 3];}function Student(name, sex, age, school, sid) {
    People.call(this, name, sex, age);
    this.school = school';
    this.sid = sid;}var xiaoming = new Student('小明', '男', 12, '學校', 123456);
  1. 組合繼承

將借用原型鏈和借用建構函式的技術組合到一起,叫做組合繼承,也叫做偽經典繼承

缺點:

組合繼承最大的問題就是無論在什麼情況下,都會呼叫兩次超類別建構函式:一次是在建立子類原型的時候,另一次是在子類建構函式的內部。

原型式繼承

Object.create()方法,可以根據指定的物件為原型建立出新物件(IE9)

var obj2 = Object.create(obj1);// 寫法2var obj2 = Object.create(obj1, {    // 第二個引數為一個物件,將要補充的屬性寫在裡面
    d: {    // 屬性的值仍然是一個物件
        value : 99     // 值為99
    }     // 可以遮蔽原型上的同名屬性});

在沒有必要 「興師動眾」 的建立建構函式,而只是想讓新物件與現有物件 「類似」 的情況下,使用Object.create() 即可勝任,稱為原型式繼承

Object.create() 的相容性寫法

在低版本瀏覽器中實現Object.create()

// 道格拉斯·克羅克福德寫的一個函數// 函數功能就是以 o 為原型,建立新物件function object(o) {
    // 建立一個臨時建構函式
    function F() {}
    // 讓這個臨時建構函式的prototype指向o, 這樣它new出來的物件,__proto__指向了o
    F.prototype = o;
    return new F();}

寄生式繼承

編寫一個函數,它可以 「增強物件」,只要把物件傳入這個函數,這個函數將以此物件為 「基礎」 建立出新物件,併為新物件賦予新的預置方法

function f(o) {
    var p = Object.create(o);
    p.display = function () {
        console.log(111);
    }
    return p;}

缺點:

由於不能做到函數複用而降低效率(方法沒有寫到prototype上)

寄生組合式繼承

通過借用建構函式來繼承屬性,通過原型鏈的混成形式來繼承方法

function inheritPrototype(subType, superType) {
    var prototype = Object.create(superType.prototype);
    subType.prototype = prototype;
}

// 父類別
function People(name, sex, age) {
    this.name = name;
    this.sex = sex;
    this.age = age;
}

People.prototype.sayHello = function() {
    console.log("hello");
}
People.prototype.sleep = function () {
    console.log("sleep");
}

// 子類
function Student(name, sex, age, school, sid) {
    People.call(this, name, sex, age);
    this.school = school;
    this.sid = sid;
}

inheritPrototype(Student, People);   // 讓Student類的Prototype指向以People.prototype為原型的一個新物件

Student.prototype.exam = function () {
    console.log("exam");
};

var xiaoming = new Student('小明', '男', 12, '學校', 123456);

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-Xbvd5MNb-1656640428439)(images/Snipaste_2022-05-26_18-13-05.png)]

instanceof運運算元

用來檢測 」某物件是不是某個類的範例「

xiaoming instanceof Student// 底層機理:檢查Student.prototype屬性是否在xiaoming的原型鏈上(多少層都行,只要在就行)

內建建構函式

JavaScript有很多內建建構函式,比如Array就是陣列型別的建構函式,Function就是函數型別的建構函式,Object就是物件型別的建構函式

內建建構函式非常有用,所有該型別的方法都是定義在它的內建建構函式的prototype上的,我們可以給這個物件新增新的方法,從而拓展某些型別的功能

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-sE1aOOg0-1656640428440)(images/image-20220526183811716.png)]

內建建構函式的關係

Object.prototype是萬物原型鏈的終點,JavaScript中函數陣列皆為物件。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-kf79HGua-1656640428441)(images/image-20220526201139877.png)]

任何函數都可以看做是Function 「new出來的」,Object是函數,所以它也是Function類的物件

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-0Ly7Sh5P-1656640428442)(images/image-20220526201656295.png)]

包裝類

包裝類的目的就是為了讓基本型別值可以從它們的建構函式的prototype上獲得方法

Math物件

Math.pow()
Math.sqrt()
Math.ceil()      // 向上取整
Math.floor()     // 向下取整
Math.round()     // 四捨五入
Math.max()      // 參數列的最大值
Math.min()

// 計算arr陣列的最大值
var arr = [3, 6, 9, 2];
var max = Math.max.apply(null, arr);

Date物件

new Date()     // 得到當前時間的日期物件
newDate(2020, 11, 1)     // 第二個引數從0開始算
new Date('2020-12-01')

常見方法

方法功能
getDate()得到日期 1 ~ 31
getDay()得到星期 0 ~ 6
getMonth()得到月份 0 ~ 11
getFullYear()得到年份
getHours()得到小時數 0 ~ 23
getMinutes()得到分鐘數 0 ~ 59
getSeconds()得到秒數 0 ~ 59

時間戳

通過getTime()方法或者Date.parse()函數可以將日期物件變為時間戳

通過new Date(時間戳)的寫法,可以將時間戳變為日期物件

var d = new Date();var timestamp1 = d.getTime();var timestamp2 = Date.parse(d);

正規表示式

正規表示式(regular expression)描述了字串的 「構成模式」,經常被用於檢查字串是否符合預定的格式要求
建立正規表示式

  1. 使用/內容/的語法形式
var str = '123456';var regxp = /^\d{6}$/;if (regxp.text(str)) {
	alert('符合規則');} else {
	alert('不符合規則');}
  1. new RegExp(‘內容’)的形式
var regxp2 = new RegExp('^\\d{6}$')

元字元

元字元功能
\d匹配一個數位
\D匹配一個非數位字元
\w匹配一個單字字元(字母、數位或下劃線)
\W匹配非單字字元
\s匹配一個空白字元,包括空格、製表符和換行符
.任意字元
^匹配開頭
$匹配結尾

不管一個符號有沒有特殊意義,都可以在其之前加上一個\以確保它表達的是這個符號本身

方括號表示法

使用方括號,如[xyz],可以建立一個字元集,表示匹配方括號中的任意字元

/^[by]\d{7}$/

使用短橫-來指定一個字元範圍,^表示否定

元字元等價的方括號表示法
\d[0-9]
\D[^0-9]
\w[A-Z-z0-9_]
\W[^A-Z-z0-9_]

量詞

量詞意義
*匹配前一個表示式0次或多次。等價於{0,}
+匹配前一個表示式1次或多次。等價於{1,}
?匹配前面一個表示式0次或1次。等價於{0,1}
{n}匹配了前面一個字元剛好出現了n次
{n,}匹配前一個字元至少出現了n次
{n,m}匹配前面的字元至少n次,最多m次

修飾符

也叫標誌(flags),用於使用正規表示式實現高階搜尋

修飾符意義
i不區分大小寫搜尋
g全域性搜尋
var re = /m/gi;var re = new RegExp('m', 'gi');

正規表示式相關方法

方法簡介
test()測試某字串是否匹配正規表示式,返回布林值
exec()根據正規表示式,在字串中進行查詢,返回結果陣列或null

字串的相關正則方法

方法簡介
search()在字串中根據正規表示式進行查詢匹配,返回首次匹配到的位置索引,測試不到則返回-1
match()在字串中根據正規表示式進行查詢匹配,返回一個陣列,找不到則返回null
replace()使用替換字串替換掉匹配到的子字串,可以使用正規表示式
split()分隔字串為陣列,可以使用正規表示式
var str = 'abc123def4567ghi89';
     
// search()方法,很像indexOf(),返回查詢到的第一個下標,如果找不到就是-1
var result1 = str.search(/\d+/g);
var result2 = str.search(/m/g);
console.log(result1);       // 3
console.log(result2);       // -1

// match()方法,返回查詢到的陣列,找不到就是null
var result3 = str.match(/\d+/g);
console.log(result3);       // ["123", "4567", "89"]

// replace()方法,進行替換
var result4 = str.replace(/[a-z]+/g, '*');      // 注意+表示貪婪的,儘可能多的連續匹配小寫字母
console.log(result4);       // *123*4567*89

// split()方法,進行字串拆為陣列
var result5 = str.split(/\d+/g);
console.log(result5);       // ["abc", "def", "ghi", ""]

【相關推薦:、】

以上就是萬字圖解JavaScript筆記總結的詳細內容,更多請關注TW511.COM其它相關文章!