JS學習之旅-day10
- 1. 作用域
- 1.1 局部作用域
- 1.2 全局作用域
- 1.3 作用域鏈
- 1.4 JS垃圾回收機制(GC)
- 1.5 閉包
- 1.6 變量提升
- 2. 函數進階
- 2.1 函數提升
- 2.2 函數參數
- 2.3 箭頭函數
- 3. 解構賦值
- 3.1 數組解構
- 3.2 對象解構
- 4. 數組遍歷
- 4.1 forEach
- 4.2 filter
1. 作用域
作用域規定了變量能夠訪問的“范圍”,分為:局部作用域、全局作用域
1.1 局部作用域
- 函數作用域:只能在函數內部訪問,外部無法直接訪問,函數執行完后,函數內部的變量會被清空。
- 塊作用域:被
{}
包裹的,使用let、const
聲明的變量會產生塊作用域,var不會產生塊作用域
1.2 全局作用域
- 寫在最外層:
1.3 作用域鏈
- 本質:底層的變量查找機制
- 變量查找機制:
- 在函數被執行時,會
優先在當前函數
作用域中查找變量 - 如果當前作用域查找不到,則會依次
逐級查找父級作用域
直到全局作用域
- 在函數被執行時,會
- 總結:
- 嵌套關系的作用域串聯起來形成了作用域鏈
- 相同作用域中按著從小到大的規則查找變量
- 子作用域可以訪問父作用域,父作用域無法訪問子作用域
1.4 JS垃圾回收機制(GC)
- JS中內存的分配和回收都是自動完成的,內存在不使用的時候會被垃圾回收器自動回收。
- 內存的生命周期:
- 內存分配:當我們聲明變量、函數、對象的時候,系統會自動為他們分配內存
- 內存使用:即讀寫內存,也就是使用變量、函數等
- 內存回收:使用完畢,由垃圾回收器自動回收不再使用的內存
- 說明:
- 全局變量一般不會回收(關閉頁面回收)
- 局部變量不被使用了,會被自動回收掉
- 內存泄露:程序中分配的
內存
由于某種原因程序未釋放
或無法釋放
叫做內存泄露
- 算法說明:
- 堆棧空間分配區別:
- 棧:由
操作系統自動分配釋放
函數的參數值、局部變量等,基本數據類型都放在棧里 - 堆:一般由程序員分配釋放,若程序員不釋放,由
垃圾回收機制
回收。復雜數據類型放在堆里
- 棧:由
- 垃圾回收機制兩種常見的算法:
引用計數法
和標記清除法
- 引用計數(不再使用)
- 嵌套引用(循環引用):如果兩個對象相互引用,盡管他們不再使用,但垃圾回收器不會進行回收,
導致內存泄露
function fn(){let o1 = {}let 02 = {}o1.a=o2o2.a=o1return ‘引用計數無法回收’ }
- 嵌套引用(循環引用):如果兩個對象相互引用,盡管他們不再使用,但垃圾回收器不會進行回收,
- 標記清除法:從
根部
掃描對象,能查找到的就是使用的,查找不到的就是要回收的
- 引用計數(不再使用)
- 堆棧空間分配區別:
1.5 閉包
-
概念:一個函數對周圍狀態的引用捆綁在一起,內部函數中訪問到其他外層函數的作用域
-
閉包 = 內層函數 + 外層函數的變量
function outer(){const a=1function f(){console.log(a)}f() } outer()
-
閉包的作用:封裝數據,提供操作,外部也可以訪問函數內部的變量
function outer() {const a = 1;function fn() {console.log(a);}return fn } const fn = outer() fn()
-
風險:內存泄露
1.6 變量提升
- 把所有var聲明的變量提升到
當前作用域
前面;let/const 不存在變量提升 - 只提升聲明,不提升賦值
- 變量提升出現在相同作用域中
2. 函數進階
2.1 函數提升
- 會把所有函數聲明提升到當前作用域的最前面
- 只提升函數聲明,不提升函數調用。(函數表達式不存在提升的現象)
//函數提升 foo() function foo(){ console.log('提升了') }//函數表達式不存在提升 bar() var bar=function(){console.log('報錯了') }
2.2 函數參數
- 動態參數:
arguments
是函數內部內置的偽數組變量,它包含了調用函數時傳入的所有實參function sum() {// arguments 動態參數 只存在函數中// arguments 是一個偽數組, 它不是一個真正的數組, 但是它有length屬性, 可以通過下標訪問元素// console.log(arguments);let total = 0;for (let i = 0; i < arguments.length; i++) {total += arguments[i];}console.log(total); } sum(1, 2); sum(1, 2, 3); sum(1, 2, 3, 4); sum(1, 2, 3, 4, 5);
- 剩余參數:允許我們將一個不定數量的參數表示為一個數組
...
是語法符號,之余最末函數形參之前,用于獲取多余
的實參- 借助
...
獲取的剩余實參,是一個真數組
function sum(a,...other) {console.log(other); } sum(1, 2); // [2] sum(1, 2, 3); // [2,3] sum(1, 2, 3, 4); // [2,3,4] sum(1, 2, 3, 4, 5); // [2,3,4,5]
- 展開運算符
...
- 可以將一個數組展開
const arr=[1,2,3] console.log(...arr) //1 2 3
- 說明
- 不會修改原數組
- 最典型的應用:求數組的最值、合并數組
const arr = [1, 2, 3, 4, 5];console.log(...arr);// 求數組最大值 console.log(Math.max(...arr));// 合并數組 const arr2 = [6, 7, 8, 9, 10]; const arr3 = [...arr, ...arr2];
- 可以將一個數組展開
2.3 箭頭函數
- 目的:更簡潔的函數寫法并且不綁定this,適用于那些
需要匿名函數
的地方 - 基本語法
// 只有一行代碼時, 可以省略大括號,return 會自動返回 const fn = (a, b) => a + b; console.log(fn(1, 2));// 只有一個形參時, 可以省略小括號 const fn2 = a => a + 1; console.log(fn2(1));// 直接返回一個對象 const fn3 = (uname) => ({ uname: uname }); console.log(fn3("張三"))
- 參數
- 箭頭函數
沒有arguments
參數,但是有剩余參數
- 箭頭函數不會創建自己的this,它會從自己的作用域鏈的上一層沿用this
- 箭頭函數
3. 解構賦值
3.1 數組解構
- 定義:將數組的單元值快速批量賦值給一系列的變量。
- 語法:
const [a,b,c] = [100,60,80]
- 代碼案例:交換變量
let x = 1; let y = 2; [x, y] = [y, x]; console.log(x, y);
3.2 對象解構
- 語法:
const { name, age } = { name: 'John', age: 20 };
- 注意:變量名和屬性名一定要相同
- 解構的變量名可以重新命名:
const { name: name1, age: age1 } = { name: 'John', age: 20 };
- 數組對象解構:
// 數組對象解構 const pig = [{ name: 'John', age: 20 }, ] const [{ name: name2, age: age2 }] = pig;
- 多級對象解構
// 多級對象解構 const person = {uname: 'John',uage: 20,address: {city: 'New York', }} const { uname, uage, address: { city } } = person;
4. 數組遍歷
4.1 forEach
- 代碼:
被遍歷的數組.forEach(function(當前數組元素,當前元素索引號){//函數體 })
- 注意:
- forEach主要是遍歷數組
- 當前數組元素是必須寫的,索引號可以省略
- 與map的區別:map有返回,forEach沒有
4.2 filter
- 篩選數組
符合條件
的元素,并返回
篩選之后元素的新數組 - 代碼:
被遍歷的數組.filter(function(當前數組元素,當前元素索引號){return 篩選條件 })