嘔心瀝血 JavaScript知識點梳理大全,超詳細 建議收藏!!!
✴️大家好,我是王同學,爆肝三天三夜王同學把JavaScript 知識點梳理了一遍,文章沒有一點套路,隻有滿滿的幹貨
✴️如果對你有幫助就給我點個贊吧,這樣我們就互不相欠了
✴️星光不負趕路人,所有的幸運都來自于堅持不懈的努力,大家一起沖沖沖~~~
一、文法和變量
(一)、前端三層
(二)、JS的書寫位置
(三)、輸出語句
(四)、變量聲明提升
變量的聲明提升:你可以提前使用一個稍後才聲明的變量,而不會引發異常
在執行所有代碼前,JS有預解析階段,會預讀所有變量的定義
二、基本資料類型
(一)、JavaScript中兩大類資料類型
(二)、typeof運算符
typeof運算符可以檢測值或者變量的類型
(三)、五種基本資料類型的typeof檢測結果
(四)、數字類型
所有數字不分大小、不分整浮、不分 正負、都是數字類型
較大數或者較小數(絕對值較小)可以寫成科學計數法
(五)、不同進制的數字
(六)、一個特殊的數字型值NaN
NaN是英語“not a number” 的意思,即不是一個數字,但它是一個數字類型的值
(七)、字元串類型
- 字元串就是人類的自然語言
- 字元串要用引号包裹,雙引号或者單引号都可以
(八)、字元串的拼接
加号可以拼接多個字元串
(九)、字元串和變量的拼接
空字元串
一些時候需要用到空字元串,直接書寫閉合的引号對即可
字元串的length屬性
字元串的length屬性表示字元串的長度
(十)、字元串常用的方法
(十一)、charAt()方法
作用:得到指定位置的字元
(十二)、substring()方法
(十三)、substr()方法
(十四)、slice()方法
(十五)、三者對比總結
(十六)、toUpperCase()和toLowerCase()
(十七)、indexOf()
(十八)、BOOlean(布爾類型)
(十九)、Undefined
一個沒有被指派的變量的預設值是undefined,而undefined的類型也是undefined,即undefined又是值,又是一種類型,這種類型隻有它自己一個值
變量提升的情況
在變量聲明提升時,變量的值也是undefined
(二十)、null類型
- null對象表示是空,它是空對象
- 當我們需要将對象銷毀,數組銷毀或者删除事件監聽時,通常将他們設定為空
(二十一)、資料類型的轉換
使用Number()函數
使用parseInt()函數
使用parseFloat()函數
(二十二)、複雜資料類型簡介
3
true
NaN
Infinity
bcd
bc
''
bc
(二十三)、表達式和運算符
表達式的種類
算術、關系、邏輯、指派、綜合
(二十四)、算術運算符
預設情況下,乘除法的優先級要高于加法和減法,必要時可以使用圓括号來改變運算的順序
加号的兩種作用
取餘運算(求模運算)
- 取餘運算也叫求模運算,用百分号來表示
- a%b表示 a除以b的餘數,它不關心整數部分,隻關心餘數
(二十五)、隐式類型轉換
如果參與運算的某操作數不是數字型,那麼JavaScript會自動将此操作符轉換為數字
隐式轉換的本質就是内部調用Number()函數
解決辦法:在進行小數運算的時候,要調用數字的toFixed ()方法保留指定的小數位
(二十六)、幂和開根号
JavaScript中沒有提供幂計算,開根号的運算符,需要使用Math對象相關的方法進行計算
(二十七)、向上取整和向下取整
(二十八)、關系表達式
(二十九)、判斷是否相等
(三十)、相等和全等
(三十一)、NaN不自等
如何判斷某變量的值為NaN?
- isNaN()函數可以用來判斷變量的值是否為NaN
- 但isNaN()也不好用,它的機理是:隻要該變量傳入Number()的執行結果是NaN,則isNaN()函數都會得到true
不相等和不全等
JS中沒有連比
判斷變量 a是不是介于3到15之間,應該怎麼寫呢?
(三十二)、非運算
置反運算的結果一定是布爾值
(三十三)、與運算
(三十四)、或運算
(三十五)、短路計算
(三十六)、邏輯運算的順序
(三十七)、指派運算符
(三十八)、快捷運算符
快捷運算符表示在原數組基礎上進一步進行運算
(三十九)、自增和自減運算符
(四十)、綜合表達式
綜合表達式的運算順序:非運算—數學運算—關系運算—邏輯運算
變量的範圍表示
知識回顧
函數
(一)、函數的定義和調用
(二)、函數的調用
執行函數體中的所有語句,就稱為函數調用
調用函數十分簡單,隻需要在函數名字後面書寫圓括号對即可
(三)、語句的執行順序
(四)、函數聲明的提升
和變量聲明提升類似,函數聲明也可以被提升
函數的表達式是不能被提升的,如果函數是用函數表達式的寫法定義的,則沒有提升的特性
(五)、函數的優先提升
<script>
//首先函數會優先提升
//變量的定義後提升 後提升并不會把先提升的覆寫掉
//變量提升隻會先提升定義 不會提升值
fun();
var fun = function() {
alert('A');
}
function fun() {
alert('B')
}
fun();
</script>
(六)、函數的參數
參數是函數内的一些特定的值,在調用函數時,必須傳入這些參數的具體的值
函數的參數有多有少,函數可以沒有參數,也可以有多個參數,多個參數之間要用逗号隔開
(七)、arguments
<script>
function fun() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
console.log('所有的參數之和為:' + sum); //110
}
fun(33, 22, 55)
</script>
(八)、函數的傳回值
函數體内可以使用return關鍵字表示“函數的傳回值”
//函數的功能是傳回兩個參數的和
function sum(a, b) {
return a + b;
}
var result = sum(3, 4);
console.log(result);
(九)、函數的傳回值
調用一個有傳回值的函數,可以被當做一個普通值,進而可以出現在任何可以書寫的地方
(十)、遇見return即退出函數
調用函數時,一旦遇見return語句則會立即退出函數,将執行權交還給調用者
1
A
B
2
結合if語句 往往不需要寫else分支了
<script>
//書寫一個函數 函數的功能是判斷一個數字是否是偶數
function checkEven(n) {
if (n % 2 == 0) return true;
return false;
}
var result = checkEven(7);
console.log(result); //false
</script>
函數像一個小工廠
(十一)、練習題
<script>
//計算一個數字的階乘
function factorial(n) {
//累乘器
var result = 1;
for (var i = 1; i <= n; i++) {
result *= i;
}
return result;
}
//窮舉法
for (var i = 100; i <= 999; i++) {
// 把數字i變為字元串
var i_str = i.toString();
var a = Number(i_str[0]);
var b = Number(i_str[1]);
var c = Number(i_str[2]);
// 根據喇叭花數來判斷
if (factorial(a) + factorial(b) + factorial(c) == i) {
console.log(i);//145
}
}
</script>
(十二)、JavaScript内置的sort()方法
這個函數中的a、b分别表示數組中靠前和靠後的項,如果需要将他們交換位置,則傳回正數,否則就傳回負數
<script>
var arr = [3, 5, 6, 1, 2];
arr.sort(function(a, b) {
return a - b;
})
console.log(arr);
var arr = [99, 55, 66, 77];
arr.sort(function(a, b) {
return b - a;
})
console.log(arr);
</script>
(十三)、什麼是遞歸?
- 函數的内部語句可以調用這個函數自身,進而發起對函數的一次疊代。
- 在新的疊代中,又會執行調用函數自身的語句,進而又産生一次疊代,當函數執行到某一次時,不再進行新的疊代,函數被一層一層傳回,函數被遞歸遞
- 歸是一種較為進階的程式設計技巧,它把一個大型複雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解。
<script>
//書寫一個函數 函數會自己調用自己 進而形成遞歸
//函數的功能就是計算某個階乘 n的階乘就是n*(n-1)的階乘
function factorial(n) {
//遞歸的出口 如果計算1的階乘,可以不用遞歸了 直接告訴你答案1
if (n == 1) return 1;
//如果詢問的不是1的階乘就傳回n*(n-1)!
return n * factorial(n - 1);
}
var result = factorial(6);
console.log(result); //720
</script>
遞歸的要素
- 邊界條件:确定遞歸到何時終止,也稱為遞歸出口
- 遞歸模式:大問題是如何分解為小問題的,也稱為遞歸體
遞歸的常見算法題
<script>
// 編寫一個函數 這個函數的功能就是傳回斐波那契數列中下标為n的那項的值
function fib(n) {
//出口 數列的小标為0和下标為1的項的值都是1
if (n == 0 || n == 1) return 1;
// 斐波那契數列的本質特征就是每一項都等于前面兩項的和
return fib(n - 1) + fib(n - 2);
}
//書寫一個循環語句 計算斐波那契數列的前15項
for (var i = 0; i < 15; i++) {
console.log(fib(i));
}
</script>
(十四)、實作深克隆
<script>
//原數組
var arr1 = [33, 44, 11, 22, [77, 88],
[11, 999]
];
//結果數組 "每一個都有一個結果"
var result = [];
//函數 這個 函數會被遞歸
function deepClone(arr) {
//周遊數組的每一項
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;
}
//測試一下
var arr2 = deepClone(arr1);
console.log(arr2);
//是否藕斷絲連
console.log(arr1[4] == arr2[4]);
arr1[4].push(99);
console.log(arr1)
console.log(arr2);
</script>
如何實作深克隆?
使用遞歸的思想,整體思路和淺克隆相似,但稍微進行一些改動,如果周遊到項是基本類型值,則直接推入結果數組,如果周遊到的項是又是數組,則重複執行淺克隆的操作。
(十五)、淺克隆
<script>
//準備原數組
var arr1 = [33, 44, 55, 66, [99, 22], 111];
//準備一個結果數組
var result = [];
//周遊原數組
for (var i = 0; i < arr1.length; i++) {
result.push(arr1[i]);
}
//輸出結果數組
console.log(result);
// 測試是否實作了克隆 ,就是說本質上是記憶體中的不同數組了
console.log(arr1 == result); // false
//測試這樣的克隆是淺克隆“藕斷絲連”
arr1[4].push(100);
console.log(result);
</script>
(十六)、全局變量和局部變量
變量的作用域
JavaScript是函數級作用域程式設計語言:變量隻在其定義時所在的function内部有意義
全局變量
如果不将函數定義在任何函數的内部,此時這個變量就是全局變量。它在任何函數内都可以被通路和更改
(十七)、遮蔽效應
遮蔽效應:如果函數中也定義了和全局同名的變量,則函數内的變量會将全局的變量遮蔽
(十八)、考慮變量提升的情況
(十九)、形參也是局部變量
<script>
var a = 10;
function fun(a) {
a++;
console.log(a); //8
}
fun(7);
console.log(a); //10
</script>
(二十)、作用域鍊
一個函數内部也可以定義一個函數,和局部變量相似,定義在一個函數内部的函數是局部函數
作用域鍊:在函數嵌套中,變量會從内到外逐層尋找他的定義
<script>
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); //40 20 30 50
}
inner();
}
fun();
</script>
不加var 将定義全局變量
在初次給變量指派的時候,如果沒有加var, 則将定義全局變量
<script>
var a = 1;
var b = 2;
function fun() {
//字母c沒有加var 關鍵字 是以他為全局變量
c = 3;
var b = 4;
b++;
c++;
}
fun();
console.log(b); //2
//在函數的外部是可以通路變量c的
console.log(c); //4
</script>
(二十一)、閉包
什麼是閉包:閉包是函數本身和該函數聲明時所處的環境狀态的組合 ,函數能夠“記憶住”其定義所處的環境,即使函數不在其定義的環境中被調用,也能通路定義時所處的環境變量
<script>
//建立一個函數
function fun() {
//定義局部變量
var name = '慕課網';
//傳回一個局部函數
return function() {
alert(name)
}
}
//調用外部函數就能得到内部函數
var inner = fun();
//定義一個全局變量
var name = 'ABC';
//執行inn函數 就相當于在 fun函數的外部執行了内部的函數
inner()
</script>
觀察閉包的現象
在JavaScript中,每次建立函數時都會建立閉包
但是,閉包往往需要将函數換一個地方執行,才能被觀察出來
閉包的用途
- 記憶性:當閉包産生時,函數所處壞境的狀态會始終保持在記憶體中,不會在外層函數調用後自動清除,這就是閉包的記憶性
<script>
function createCheckTemp(standardTemp) {
function checkTemp(n) {
if (n <= standardTemp) {
alert("你的體溫正常")
} else {
alert("你的體溫偏高")
}
}
return checkTemp;
}
//建立一個 checkTemp函數,它以37.1為标準線
var checkTemp_A = createCheckTemp(37.1);
//建立一個 checkTemp函數,它以37.3為标準線
var checkTemp_B = createCheckTemp(37.3);
checkTemp_A(37.2);
checkTemp_B(37.2);
</script>
閉包的用途—模拟私有變量
<script>
//封裝一個變量 這個函數的功能是私有化變量
function fun() {
// 定義一個局部變量 a
var a = 0;
return {
getA: function() {
return a;
},
add: function() {
a++;
},
pow: function() {
a *= 2;
}
}
}
var obj = fun();
//如果想在fun函數外面使用變量a唯一的辦法就是調用getA() 方法
console.log(obj.getA());
//想讓 a進行加一操作
obj.add();
console.log(obj.getA());
obj.pow();
console.log(obj.getA());
</script>
使用閉包的注意點
不能濫用閉包,否則會造成網頁的性能問題,嚴重時可能會導緻記憶體洩漏,所謂記憶體洩漏是指程式中已動态配置設定的記憶體由于某種原因未釋放或者無法釋放
<script>
function addCount() {
var count = 0;
return function() {
count = count + 1;
console.log(count);
}
}
var fun1 = addCount();
var fun2 = addCount();
fun1(); //1
fun2(); //1
fun2(); //2
fun1(); //2
</script>
(二十二)、IIFE
IIFE(Immediately Invoked Function Expression立即調用函數表達式)是一種特殊的JavaScript函數寫法,一旦被定義,就立即被調用
形成IIFE 的方法
函數不能直接加圓括号被調用
函數必須轉為函數表達式才能被調用
IIFE的作用
為變量指派:當給變量指派需要一些較為複雜的計算的時候(如if語句)使用IIFE顯得文法更緊湊
IIFE可以在一些場合(如for循環)将全局變量變為局部變量文法顯得更緊湊
(四十一)、流程控制語句
if語句的基本使用
//要求輸入三位數
var n = Number(prompt('請輸入三位數'));
//對使用者輸入的值進行合法驗證
if (!isNaN(n) && 100 <= n && n <= 999) {
var a = parseInt(n / 100);
var b = parseInt(n / 10) % 10;
var c = n % 10;
if (Math.pow(a, 3) + Math.pow(b, 3) + Math.pow(c, 3)) {
alert('是水仙花數');
}
} else {
alert('您輸入的數字不合法')
}
(四十二)、switch語句
switch語句的用途:當一個變量被分類讨論的情形
switch語句并不像if語句那樣當執行了某個分支後會自動跳出if語句,我們必須主動調用break語句來跳出break語句體,如果不書寫break,則後面的所有case都将被視為比對,直到遇見break
<script>
//讓使用者輸入月份
var month = Number(prompt('請輸入月份'));
//分類讨論
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
alert('這個月有31天');
break;
case 4:
case 6:
case 9:
case 11:
alert('這個月有28天');
break;
case 2:
alert('這個月有28天或者29天');
break;
default:
alert('你輸入的月份有誤')
}
</script>
(四十三)、三元運算符
三元運算符的用途:根據某個條件是否成立,在兩個不同值中選擇變量的值
(四十四)、for循環
for循環語句的執行機理
準确周遊for循環
<script>
//sum是累加器 初始值是0
for (var i = 1, sum = 0; i <= 100; i++) {
sum += i;
}
console.log(sum); //5050
</script>
//窮舉法
for (var i = 1; i < 100; i++) {
if (i % 3 == 1 && i % 4 == 2 && i % 5 == 3) {
console.log(i); //58
}
}
(四十五)、while循環語句
- while語句也是一種循環語句,是一種不定範圍的循環,和for循環各有不同的用武之地,幾乎所有的循環都同時提供for循環和while循環
- while語句事先不指定循環的開始,結束的範圍,隻要測試條件滿足,就一直執行循環
- while循環沒有顯示定義循環變量,必須自己在while循環外先定義好循環變量,有時候甚至沒有循環變量
- 循環體内的語句,必須使循環測試條件趨向不成立,否則會死循環
var i = 1;
while (i <= 100) {
console.log(i);
i++;
}
//尋找滿足n的平方和大于456789的最小整數
//窮舉法 從1開始試驗
var n = 1;
while (n * n < 456789) {
n++;
}
console.log(n); //676
var n = 1;
var sum = 0;
while (sum < 500) {
sum += n;
n++;
}
//注意這裡有個“出一錯誤”
console.log(n - 1); //32
(四十六)、break和continue
break表示立即終止這個循環,他隻能用在循環語句中,在for循環和while循環中都可以使用
continue用于跳過循環中的一個疊代,并繼續執行循環中的下一個疊代,for循環中經常使用continue
(四十七)、do while語句
<script>
//後判斷的一種形式 至少執行一次循環體
do {
console.log('★');
} while (false); //★
</script>
var n = 1;
do {
console.log(n);
n++
} while (n <= 100);
(四十八)、随機數函數
随機數函數得到0到1之間的小數
(四十九)、do while 小案例
<script>
do {
var dx = parseInt(Math.random() * 9) - 4;
var dy = parseInt(Math.random() * 9) - 4;
}
while (dx == 0 && dy == 0);
console.log(dx, dy);
</script>
(五十)、猜數字小遊戲
<script>
//随機一個數字2-99
var answer = parseInt(Math.random() * 98) + 2;
//此時範圍的最大值和最小值這個數字是用來提示使用者的
var min = 1;
var max = 100;
//不斷的重複 就用死循環
while (true) {
//詢問使用者猜測的數字
var n = Number(prompt('請猜猜數字' + min + '~' + max));
//驗證使用者輸入的數字是否在範圍内
if (n <= min || n >= max) {
alert('你輸入的數字不在範圍内')
//放棄這次循環,就開啟下一次疊代
continue;
}
//判斷使用者輸入的數字和answer的關系
if (n > answer) {
alert('你輸入的數字太大了');
//因為使用者輸入的數字較大,是以可以讓此時的最大範圍的數字變為使用者輸入的值
max = n;
} else if (n < answer) {
alert('你輸入的數字太小了')
//因為使用者輸入的數字較小,是以可以讓此時的最小範圍的數字變為使用者輸入的值
min = n;
} else {
alert('猜對了');
//結束死循環
break;
}
}
</script>
(五十一)、什麼是算法
- 算法是指解題方案的準确而完整的描述,是一系列解決問題的清晰指令,算法代表着用系統的方法描述解決問題的政策機制,也就是說,能夠對一定規範的輸入,在有限時間内獲得所要求的輸出
- 算法就是把一個問題,拆解為計算機能夠一步一步執行的步驟
優秀算法的要求
- 正确性
- 健壯性
- 可讀性
(五十二)、僞代碼
(五十三)、算法如何培養
- 多敲、多練、多總結
- 經典的業務需求場景要熟記心間
(五十四)、累加器
//使用者輸入數字n
var n = Number(prompt('請輸入數字'));
//累加器
var sum = 0;
//周遊分母
for (var i = 2; i <= n; i++) {
sum += (i + 1) / i
}
alert(sum.toFixed(2));
(五十五)、累乘器
<script>
//計算階乘
var n = Number(prompt('請輸入數字'));
//累乘器 從1開始 如果要從0開始 0乘以任何數字都為0
var result = 1;
//倒着周遊 計算階乘
for (var i = n; i >= 1; i--) {
result *= i;
}
alert(result);
</script>
(五十六)、窮舉法
計算機最突出的能力就是計算,他沒有歸納總結,推理邏輯的能力,是以人們使用計算機解決問題的時候,要揚長避短,充分發揮計算機的優勢,而不要讓他們進行邏輯推理,窮舉法就是這樣一種算法思想。
什麼是窮舉法?
窮舉法,顧名思義,是指根據題目的條件确定答案的大緻範圍,并在此範圍内對所有可能的情況逐一驗證,直到全部的情況驗證完畢,若某個情況符合題目的條件,則為本題的一個解,若全部情況驗證後都不符合條件,則本題無解。
//窮舉法
for (var i = 1; i <= 100; i++) {
if (i % 3 == 0 && i % 5 == 0) {
console.log(i);
}
}
//尋找約數
var n = Number(prompt('請輸入數字:'));
//窮舉法
for (var i = 1; i <= n; i++) {
if (n % i == 0) {
console.log(i);
}
}
//尋找水仙花數
for (var i = 100; i < 1000; i++) {
var i_str = i.toString();
var a = i_str.charAt(0);
var b = i_str.charAt(1);
var c = i_str.charAt(2);
if (Math.pow(a, 3) + Math.pow(b, 3) + Math.pow(c, 3) == i) {
console.log(i);
}
}
(二十三)、DOM簡介
(二十四)、nodeType常用的屬性
(二十五)、通路元素節點
所謂的通路元素節點就是指得到,擷取頁面上的元素節點
對節點進行任何的操作,就是要得到節點,通路節點主要依靠document對象
認識document對象
(二十六)、通路元素節點常用的方法
(二十七)、getElementById ()
- 如果頁面上有相同的id元素 則隻能得到第一個
- 不管元素藏得位置有多深,都能通過Id把它找到
延遲運作
(二十八)、getElementsByTagName()
注意事項:
- 數組友善周遊,進而可以批量操控元素節點
- 即使頁面上隻有一個指定标簽名的節點,也得到長度為1的數組
- 任何一個節點元素也可以調用getElementsByTagName()方法,進而得到内部的某種類的元素節點
(二十九)、getElementsByClassName()
(三十)、querySelector()
(三十一)、querySelectorAll()
(三十一)、節點的關系
文本節點也屬于節點
在标準的W3C規範中,空白文本節點也應該算作節點,但是在IE8以及以前的節點中也會有一定的相容問題,他們不把空文本節點當做節點
(三十二)、節點的操作
改變元素節點中的内容可以使用兩個相關的屬性
innerHTML屬性能夠以HTML文法設定節點中的内容
innerText屬性隻能以純文字的形式設定節點中的内容
(三十三)、如何改變元素節點的CSS樣式
(三十四)、如何改變元素節點的HTML屬性
(三十五)、節點的建立
appendChild()
insertBefore()
<body>
<div id="box">
<p>我是原本的段落0</p>
<p>我是原本的段落1</p>
<p>我是原本的段落2</p>
</div>
<script>
var oBox = document.getElementById('box');
var oPs = oBox.getElementsByTagName('p');
//建立孤兒節點
var oP = document.createElement('p');
//設定内部文字
oP.innerHTML = '我是新來的'
//上樹
//oBox.appendChild(oP);
oBox.insertBefore(oP, oPs[0])
</script>
</body>
(三十六)、移動節點
(三十七)、删除節點
(三十八)、克隆節點
(三十九)、事件監聽
什麼是事件:使用者與網頁的互動動作
比如:當使用者點選元素時,當滑鼠移動到元素上時,當文本框的内容被改變時、當鍵盤在文本框中被按下時,當網頁加載完畢時……
什麼是事件監聽?
監聽,顧名思義,就是讓計算機能夠發現這個事件發生了,進而執行程式員預先編寫的一些程式
<style>
div {
width: 200px;
height: 200px;
background-color: #ccc;
}
</style>
</head>
<body>
<div id="box">
</div>
<script>
var oBox = document.getElementById('box');
//給這個盒子添加點選事件監聽
oBox.onclick = function() {
alert('你好,我是點選事件的函數');
}
</script>
(四十)、常見的滑鼠事件監聽
(四十一)、常見的鍵盤事件
(四十二)、常見的表單事件監聽
(三十九)、事件監聽
什麼是事件:使用者與網頁的互動動作
比如:當使用者點選元素時,當滑鼠移動到元素上時,當文本框的内容被改變時、當鍵盤在文本框中被按下時,當網頁加載完畢時……
什麼是事件監聽?
監聽,顧名思義,就是讓計算機能夠發現這個事件發生了,進而執行程式員預先編寫的一些程式
<style>
div {
width: 200px;
height: 200px;
background-color: #ccc;
}
</style>
</head>
<body>
<div id="box">
</div>
<script>
var oBox = document.getElementById('box');
//給這個盒子添加點選事件監聽
oBox.onclick = function() {
alert('你好,我是點選事件的函數');
}
</script>
(四十)、常見的滑鼠事件監聽
(四十一)、常見的鍵盤事件
(四十二)、常見的表單事件監聽
(四十五)、常見的頁面監聽事件
(四十六)、事件傳播
<script>
var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");
var box3 = document.getElementById("box3");
// box1.onclick = function() {
// alert('A');
// }
// box1.onclick = function() {
// alert('B '); //B
// }
box2.addEventListener("click", function() {
alert('C ');
}, false)
box2.addEventListener("click", function() {
alert('D '); //先C再D
}, false)
</script>
(四十七)、事件對象
事件處理函數提供一個形式參數,它是一個對象,封裝了本次事件的細節,這個參數通常用單詞event或者字母e來表示
(四十八)、滑鼠位置
<style>
* {
margin: 0;
padding: 0;
}
#box {
width: 200px;
height: 200px;
background-color: #333;
margin: 100px;
padding: 50px;
}
body {
height: 2000px;
}
#info {
font-size: 30px;
}
</style>
</head>
<body>
<div id="box">
</div>
<div id="info">
</div>
<script>
var oBox = document.getElementById('box');
var oInfo = document.getElementById('info');
oBox.onmouseover = function(e) {
oInfo.innerHTML = 'offsetX / Y: ' +
e.offsetX + ',' + e.offsetY + '<br/>' + 'clientX/Y:' + e.clientX + ',' + e.clientY;
}
</script>
(四十九)、字元碼
鍵碼
<script>
var oList = document.getElementById('list');
var lis = oList.getElementsByTagName('li');
// 書寫循環語句 批量添加監聽
for (var i = 0; i < lis.length; i++) {
lis[i].onclick = function() {
this.style.color = ' red';
}
}
</script>
批量添加事件監聽的性能問題
每一個事件監聽注冊都會消耗一定的系統記憶體,而批量添加事件會導緻監聽數量太多,記憶體消耗十分的大
實際上,每個li 的事件處理函數都是不同的函數,這些函數本身也會占用記憶體
(五十)、事件委托
利用事件冒泡機制,将後代元素事件委托給祖先元素
<button id="btn">按我建立一個新清單項</button>
<ul id="list">
<li>清單項</li>
<li>清單項</li>
<li>清單項</li>
</ul>
<script>
var oList = document.getElementById('list');
var oBtn = document.getElementById('btn')
oList.onclick = function(e) {
//e.target表示使用者真正點選的那個元素
e.target.style.color = 'red';
// e.currentTarget表示整個清單項
// e.currentTarget.style.color = 'blue';
}
oBtn.onclick = function() {
//建立新的li元素
var oLi = document.createElement('li');
//寫内容
oLi.innerText = ' 我是新來的';
//上樹
oList.appendChild(oLi);
}
</script>
(五十一)、定時器和延時器
函數的參數
具名函數也可以傳入setInterval
什麼是具名函數? 什麼是匿名函數?
具名函數,故名思意就是有名字的函數,具名函數一般是我們定義的最多的一種
// 函數
function fn() {
console.log('我是具名函數')
console.log('看,我有名字')
console.log('我的名字叫 fn')
}
fn()
fn()
匿名函數
沒有名字的函數,匿名函數我們也随處可見,我們來寫幾個匿名函數
setTimeout(function () {
console.log('我是匿名函數,我被用于定時器參數傳遞')
}, 1000)
let arr = [1, 2, 3]
arr.forEach(function (item) {
console.log('我是匿名函數,我被用于回調函數參數')
})
let box = document.querySelector('#box')
box.onclick = function () {
console.log('我是匿名函數,我被用于綁定事件')
}
(五十二)、清除定時器
<h1 id="info"></h1>
<button id="btn1">開始</button>
<button id="btn2">暫停</button>
<script>
var oInfo = document.getElementById('info')
var btn1 = document.getElementById("btn1");
var btn2 = document.getElementById("btn2");
var a = 0;
//設定一個全局變量
var timer;
btn1.onclick = function() {
//為了防止定時器疊加 我們應該在設定定時器之前清除定時器
clearInterval(timer)
//更改全局變量的值為一個定時器實體
timer = setInterval(function() {
oInfo.innerText = ++a;
}, 1000)
}
btn2.onclick = function() {
clearInterval(timer)
}
</script>
延時器
<button id="btn1">2秒後彈出你好</button>
<button id="btn2">2秒後取消彈出</button>
<script>
var btn1 = document.getElementById("btn1");
var btn2 = document.getElementById("btn2");
var timer;
btn1.onclick = function() {
timer = setTimeout(function() {
alert('你好,世界!');
}, 2000)
}
btn2.onclick = function() {
clearInterval(timer);
}
</script>
(五十三)、初識異步函數
(五十三)、什麼是BOM?
- Window對象是目前JS腳本運作所處的視窗,而這個視窗中包含DOM對象,window. document屬性就是document對象
- 在有标簽頁的浏覽器功能中,每個标簽都擁有自己的window對象,也就是說,同一個視窗的标簽頁之間不會共享一個window對象
全局變量是window的屬性
以上結果就意味着,多個JS檔案之間是共享作用域的,即JS檔案沒有作用域隔離的功能
内置函數普遍是window的方法
(五十四)、視窗尺寸相關的屬性
(五十五)、resize事件
(五十六)、已卷動的高度
(五十七)、scroll事件
(五十八)、Navigator對象
(五十九)、History對象
常用的操作就是模拟浏覽器的回退按鈕
(六十)、Location對象
重新 加載目前頁面
(六十一)、BOM特效開發傳回頂部
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
height: 5000px;
background-image: linear-gradient(to bottom, blue, green, yellow);
}
.backtotop {
width: 60px;
height: 60px;
background-color: rgba(255, 255, 255, 0.6);
position: fixed;
bottom: 100px;
right: 100px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="backtotop" id="backtotopbtn">傳回頂部</div>
<script>
var backtotopbtn = document.getElementById("backtotopbtn");
var timer;
backtotopbtn.onclick = function() {
//設定表先關
clearInterval(timer);
//設定定時器
timer = setInterval(function() {
//讓scrollTop不斷減少
document.documentElement.scrollTop -= 80;
// 定時器停下來
if (document.documentElement.scrollTop <= 10) {
clearInterval(timer);
}
}, 20)
}
</script>
</body>
</html>
面向對象
(六十二)、認識對象
對象是鍵值對的集合,表示屬性和值的映射關系
(六十三)、對象的文法
屬性的通路
可以使用“點文法”通路對象中指定鍵的值
如果屬性不符合JS辨別符的命名規範,則必須使用方括号的寫法來通路
如果屬性名以變量的形式存儲,則必須使用方括号的形式
屬性的更改
直接使用指派運算符重新對某屬性指派即可更改屬性
屬性的建立
如果對象本身沒有某個屬性值,則用點文法指派時,這個屬性就會被建立出來
屬性的删除
如果要删除某個對象的屬性,需要使用delete操作符
(六十四)、對象的方法
如果某個屬性值是函數,則它也被稱為對象的方法
方法的調用:使用點文法可以調用對象的方法
方法和函數
方法和函數,隻不過方法是對象的函數屬性,它需要用對象打點調用
對象的周遊
和周遊數組類似,對象也可以被周遊,周遊對象需要使用for…in…循環,使用for…in循環需要可以周遊對象的某個鍵
(六十五)、基本類型和引用類型的值
對象是引用類型值
對象是引用類型的值,這就意味着:
<script>
var obj1 = {
a: 1,
b: 2,
c: [33, 44, {
m: 55,
n: 66,
p: [77, 88]
}]
};
//實作深克隆
function deepClone(o) {
//要判斷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;
}
var obj2 = deepClone(obj1);
console.log(obj2);
//看是否有藕斷絲連的情況
//引用類型的值互不相等
console.log(obj1.c == obj2.c); //false
obj1.c.push(99);
console.log(obj2); //obj2不變 因為沒有藕斷絲連的現象
obj1.c[2].p.push(99);
console.log(obj1);
</script>
(六十六)、認識上下文
什麼是上下文?
函數的上下文
- 函數中可以使用this關鍵字,它表示函數的上下文
- 與中文中的這類似,函數中的this具體指代什麼必須通過調用函數時的前言後語來判斷
函數中的this
由以上可知,函數的上下文是由函數的調用方式來決定的,也就是說同一個函數,用不同的形式來調用它,則函數的上下文不同
以上兩個例子:
情形一:對象打點調用函數,函數中的this指代這個打點的對象
情形二:圓括号直接調用函數,函數中的this指代的是window對象
來個案例
這個題目中這兩個this指代的是啥:不知道!!因為函數隻有被調用的時候它的上下文才能被确定,是以 函數的上下文是不能被确定的。
輸出3
輸出NaN
規則1題目舉例—第一小題
規則1題目舉例—第二小題
規則1題目舉例—第三小題
規則二
規則二:圓括号直接調用函數,則函數的上下文是window對象
規則二—第一題
規則二—第二題
上下文規則三
規則三:數組(類數組對象)枚舉出函數進行調用,上下文是這個數組(類數組對象)
規則三—第一題
什麼是類數組對象?
所有鍵名為自然數序列(從0開始),且有length屬性的對象
arguments對象是最常見的類數組對象,它是函數的實參清單
規則三題目一
規則四
IIFE函數,上下文是window對象
規則五
規則五:定時器,延時器調用函數,上下文是window對象
輸出結果:7
上下文規則六
規則六:事件處理函數的上下文是綁定事件的DOM元素
練習小demo
(六十七)、call和apply能夠指定函數的上下文
(六十八)、 call和apply的差別
到底使用call還是apply?
(六十九)、上下文規則總結
(七十)、用new操作符調用函數
JS規定,使用new操作符調用函數會進行四步走:
- 函數體内會自動建立出一個空白對象
- 函數的上下文(this)會指向這個對象
- 函數體内的語句會執行
- 函數會自己傳回上下文對象,即使函數沒有return語句
(七十一)、構造函數
什麼是構造函數?
- 用new調用一個函數,這個函數就被稱為構造函數,任何函數都可以是構造函數,隻需要用new調用它
- 顧名思義,構造函數用來構造新對象,它内部的語句将為新對象添加若幹屬性和方法,完成對象的初始化
- 構造函數必須使用new關鍵字調用,否則不能正常工作,是以,開發者約定構造函數命名時首字母要大寫
如果不用new調用構造函數
構造函數中的this不是函數本身
嘗試為對象添加方法
(七十二)、類與執行個體
構造函數和類
- Java、C++等是“面向對象”(object-oriented)的語言
- JavaScript是“基于對象(object-based)的語言”
- JavaScript中的構造函數可以類比于OO語言中的類,寫法的确類似,但和真正OO語言還是有本質的不同
(七十三)、prototype和原型鍊查找
什麼是prototype?
- 任何函數都有prototype屬性,prototype表示“原型”的意思
- prototype屬性值是一個對象,它預設擁有constructor屬性指回函數
原型鍊查找
(七十四)、hasOwnProperty方法
(七十五)、in
in運算符隻能檢查某個屬性或者方法是否可以被對象通路,不能檢查是否是自己的屬性或者方法
原型鍊的終點
關于數組的原型鍊
(七十六)、繼承
兩個無關的類
People和Student的關系
- People類擁有的屬性和方法Student類都有,Student類還擴充了一些屬性和方法
- Student是一種People,兩類之間是“is a kind of”關系
- 這就是繼承關系,Student類繼承People類
-
繼承描述了 兩個類之間的關系,比如學生是一種人,是以人類和學生之間就構成繼承的關系
- People是“父類”(“超類”,“基類”);Student是“子類”(或者派生類)
更多的繼承關系舉例
(七十七)、JavaScript中如何實作繼承
實作繼承的關鍵在于:子類必須擁有父類的全部屬性和方法,同時還應該能定義自己特有的屬性和方法,使用特有的原型鍊特性來實作繼承,是普遍的做法
通過原型鍊來實作繼承
(七十八)、面向對象到底是什麼
- 面向對象的本質:定義不同的類,讓類的執行個體工作
- 面向對象的優點:程式編寫更清晰,代碼結構更加嚴密,使代碼更健壯易于維護
- 面向對象經常用到的場合,需要封裝和複用性的場合(元件思維)
(七十九)、包裝類
包裝類知識點總結
包裝類的目的就是為了讓基本類型值可以從他們的構造函數的prototype上獲得方法
(八十)、Math對象的方法
(八十一)、Date()日期對象
時間戳
- 時間戳表示1970年1月1日零點距離某時刻的毫秒數
- 通過getTime()方法或則Date.parse()函數可以将日期對象變為時間戳
- 通過new Date(時間戳)的寫法,可以将時間戳變為日期對象
(八十二)、正規表達式知識點總結
一、什麼是正規表達式
- 正規表達式也稱為規則表達式,就是普通字元和特殊字元構成的一個表達式
- 作用就是用來檢驗字元串是否符合格式要求,或者在字元串中查找是否有符合格式要求的字元串。
二、如何建立正規表達式
- 利用構造方法建立:
var 正規表達式的名稱=new RegExp('正規表達式内容','修飾符');
- 利用字面量形式建立:
var 正規表達式的名稱=/ 正規表達式内容/修飾符;
三、正規表達式的常用方法—test方法
- 作用:驗證字元串是否符合正規表達式的格式要求
- 格式:
正規表達式.test(字元串)
- 傳回值:true(符合要求)、false(不符合)
四、正規表達式的構成
(一)普通字元
- 如字母、數字0-9、a-z、A-Z、_
(二)、特殊字元(元字元)
(1)、定位符
^:表示以某個字元開頭,如/^a/表示字元串以字母a開頭
$:表示以某個字元結尾,如/$a/表示字元串以a結尾
(2)、表示數量的限定符
-
表示它前面的字元的個數為0到無窮多個,如/a*/表示a的個數最少0個,最多無限個*:
- +:表示他前面的字元的個數為1到無窮多個。如/a+/表示 a的個數最少1個,最多無限個
- ?:表示他前面的字元為0到1個。如/a?/表示a的個數最少0個,最多一個
- {n}:表示他前面的字元隻能是n個.如/a{3}/表示字元串中包含3個字元a
- {n, }:表示他前面的字元為n到無窮多個,如/a{3, }/表示字元串 a的個數大于等于3個
- {n,m}:表示他前面的字元的個數為n-m個.如a{1,5}表示a的個數為1-5個
(3)、轉義字元
轉義字元:所謂轉義字元就是指在普通字元的前面加反斜線,使得他具有特定的功能和含義,也可以在具有特定的功能和含義的字元前面加反斜線,将他轉換為普通字元 如:\d表示任意一個數字/\表示将正規表達式中的斜線轉換為普通的斜線
- \d:表示任意一個數字
- \D:表示任意一個非數字
- \w:表示任意一個字母、數字、下劃線
- \W:任意一個非字母數字下劃線
- \s:表示任意一個空白符,比如制表符、空格
- \S:任意一個非空白符
(4)、備選字元集
-
:中括号裡面的值表示字元串中可以比對到的任意一個值[值1 值2 值3 值4]
-
表示值1到值n間的任意一個值為備選選項[值1-值n]:
-
:表示字元串中不可以包含中括号裡面的任意一個值[^值1 值2 值3]
-
:表示任意的一個漢字[\u4e00-\9fa5]
四、正規表達式的比對模式
1)貪婪模式:指正規表達式在對字元串進行比對時盡可能多的比對字元,預設就是貪婪模式
2)懶惰模式:指正規表達式在對字元串進行比對時盡可能少的比對字元,預設是貪婪模式,如果要将貪婪模式轉化為懶惰模式,需要在數量修飾符後面加問号
(五)、字元串對象中和正規表達式結合使用的方法
(一)、split方法
- 作用:将字元串轉化為數組
- 格式:
字元串名稱.splite('分隔符');
(二)、match方法
- 作用:從字元串中查找到符合條件的
- 格式:字元串.match(子串);
- 傳回值:由子串形成的數組,預設隻傳回找到符合條件的第一個子串,如果要找到符合條件的所有的子串需要使用正規表達式作為參數
(三)、repalce方法
- 作用:替換字元串中指定的子串
- 格式:
字元串.repalce.('要被替換的子串','新的子串');
- 傳回值:預設情況下,隻替換符合條件的第一個子串,如果要将所有的子串替換掉,則需要使用正規表達式 且這個正規表達式需要使用修飾符g,如果要替換的子串不存在則傳回原串
(四)、search方法
- 作用:在字元串從左向右查找子串位置,如果存在則傳回該子串對應的下标,否則傳回-1,功能類似于
方法indexOf
- 格式:
字元串.search('子串');
- 注意:該方法可以和正規表達式結合使用,但是就算正規表達式中有修飾符g,在比對的時候也隻能傳回查找到的第一個子串
六、正規表達式常用的修飾符
- i:表示忽略大小寫
- g:表示全局比對
- ig/gi:表示既忽略大小寫也全局比對