【前端】ES6一本通_劃重點_補充面試題

近兩天更新完基本內容,后續長期更新,建議關注收藏點贊。
ES6(ECMAScript 2015)是現代 JavaScript 的基礎,在前端面試中非常常見。

  • 本文已匯總的本站筆記
    ES6最重要10特性
    對象新增
    數組新增
    異步、生成器
    Promise
    模塊化
    類、繼承
    async / await
    set / weakset

目錄

  • 變量聲明(let、const、var)
  • 解構賦值Destructuring Assignment
  • 模板字符串
  • 箭頭函數(Arrow Function)
  • 默認參數 & 剩余參數 & 擴展運算符(...)
  • 對象字面量增強
  • Symbol
  • Set 和 Map
  • Promise(異步編程)
  • 類(class)和繼承
  • 模塊化(ES Modules)
  • 迭代器與生成器(進階)
  • 可選鏈 & 空值合并運算符(ES2020+)
  • 其他
    • ?WeakSet
    • async/await


  • 擴展
    ES6+(7~12)
    Math數字新增

變量聲明(let、const、var)

  • var 全局;let和const是塊級作用域,僅在某一塊有效。
  • const是常量不可改動其引用對象,既然是常量不能重新進行賦值,如果是基本數據類型,不能更改值,如果是復雜數據類型,不能更改地址值。const聲明時必須賦值。
  • ???????let 和 const 不存在變量提升,在賦值前不可訪問->有“暫時性死區TDZ“
    在這里插入圖片描述

解構賦值Destructuring Assignment

  • 如果解構不成功,變量跟數值個數不匹配的時候,變量的值為undefined。解構賦值解 undefined:數組解構允許、對象結構不允許、帶默認值的解構允許
  • 數組解構用中括號包裹,多個變量用逗號隔開,對象解構用花括號包裹,多個變量用逗號隔開
const [a, b = 2] = [1]; // a = 1, b = 2
const { x, y } = { x: 10, y: 20 };let x = 1, y = 2;
[x, y] = [y, x]; // 交換變量let[a,b,c]=[1,2,3];
let [, a, , b] = arr;//JSON中的解構賦值 
let json={name:'a',age:18}; 
let {n,a}=json;//都是undefined 
let {name,age}=json;//必須名字對應上
//起別名let {name: myName, age: myAge} = json; // myName myAge 屬于別名console.log(myName); // 'a' console.log(myAge); // 18
//對象解構
function show({x, y}) {//從傳入的對象中提取 x 和 y 屬性并將它們作為函數的局部變量使用console.log(x, y);
}

模板字符串

  • 模板字符串和傳統字符串拼接的區別?
項目傳統字符串拼接模板字符串
引號單引號 ' 或雙引號 "反引號
拼接方式使用 + 拼接使用 ${} 插值
多行字符串需要手動加 \n+支持直接換行
支持表達式不直觀直接寫表達式、函數、變量等${func(a)}

箭頭函數(Arrow Function)

箭頭函數屬于表達式函數,因此不存在函數提升
箭頭函數中沒有 arguments,只能使用 … 動態獲取實參
簡化了函數表達式的寫法,并且不綁定 this,即 this 始終指向定義時的上下文。
箭頭函數不能當構造函數。

  • 箭頭函數和普通函數有什么區別
    箭頭函數沒有prototype,所以箭頭函數本身沒有this,使用new調用箭頭函數會報錯 TypeError: fun is not a constructor,不能當構造函數
    箭頭函數 沒有自己的 this、arguments、super,箭頭函數的this指向繼承自外層,且不能通過 call/bind/apply 改變
    不可以使用yield命令,因此箭頭函數不能用作 Generator 函數。
  • call() 和 apply() 對箭頭函數的影響
    對于普通函數,call() 和 apply() 可以顯式地改變 this 綁定。但對于箭頭函數來說,不能改變
  • 何時使用箭頭函數
    適用于回調函數,例如 setTimeout,避免 this 綁定錯誤
    適用于類方法,防止 this 綁定丟失
  • 優點
    解決了this執行環境所造成的一些問題。比如:解決了匿名函數this指向的問題(匿名函數的執行環境具有全局性),包括setTimeout和setInterval中使用this所造成的問題
    處理回調函數時特別有用,避免了this綁定問題。
  • 箭頭函數有兩種格式。
  1. 只包含一個表達式,連{ … }和return都省略掉了。自動作為返回值被返回
  2. 可以包含多條語句,這時候就不能省略{ … }和return。如果參數不是一個,就需要用括號()括起來。
const add = (a, b) => a + b;
let show=(...args)=>{//操作return;
}// 兩個參數:
(x, y) => x * x + y * y// 無參數:
() => 3.14// 可變參數:
(x, y, ...rest) => {var i, sum = x + y;for (i=0; i<rest.length; i++) {sum += [i];}return sum;
}如果要返回一個對象,就要注意,如果是單表達式,這么寫的話會報錯:
x => { foo: x }
正確寫法:
x => ({ foo: x })
  • 輸出練習
//例子1
const obj = {value: 42,getValue: () => {console.log(this.value);}
};
obj.getValue(); // undefined,this 不是 obj,而是外層作用域的 this
obj.getValue.call({ value: 100 }); // 仍然是 undefined,call() 無法改變 this//例子2
function outer() {const arrowFunc = () => {console.log(this); // 取決于 outer() 調用時的 this};arrowFunc();
}const obj1 = { method: outer };
obj1.method(); // this 是 obj1const obj2 = { method: outer.bind({ x: 1 }) };
obj2.method(); // this 是 { x: 1 },但箭頭函數內的 this 仍然是 obj2.method() 調用時的 this//例子3
var obj = {birth: 1990,getAge: function (year) {var b = this.birth; // 1990var fn = (y) => y - this.birth; // this.birth仍是1990return fn.call({birth:2000}, year);//2015-1990}
};
obj.getAge(2015); // 25//例子4
const obj = { name: '張三'} function fn () { console.log(this);//this 指向 是obj對象return () => { console.log(this);
//this 指向 的是箭頭函數定義的位置,
//那么這個箭頭函數定義在fn里面,而這個fn指向是的obj對象,所以這個this也指向是obj對象} } const resFn = fn.call(obj); resFn();

默認參數 & 剩余參數 & 擴展運算符(…)

ES6中,函數也可以給默認參數了

  • ...args 是什么?與 arguments 區別?
    ...args 是 剩余參數(rest parameters) 的語法,是 ES6 引入的標準,用于收集函數的多余參數為一個數組。它與傳統的 arguments 類似,但更強大、更靈活。
對比點...argsarguments
類型真正的數組 Array類數組對象(非真正數組)
是否可用于箭頭函數? 可用? 不可用
是否支持解構、數組方法? 支持(如 map, reduce? 不支持直接用數組方法
是否明確命名? 參數名明確(如 args)? 不明確,只有 arguments
可讀性? 好? 較差
  • 擴展運算符Spread & Rest
    如果傳入的參數連正常定義的參數都沒填滿,最后的擴展參數會接收一個空數組(注意不是undefined),但固定的參數如果沒傳會是undefined
    • 作用
      合并、復制數組、傳參數組
      參數收集、解構
      合并、復制對象
      字符串展開為數組
// 擴展數組
const arr1 = [1, 2];
const arr2 = [...arr1, 3, 4];// 擴展對象
const obj1 = { name: 'Alice' };
const obj2 = { ...obj1, age: 25 };// Rest 參數(收集函數的剩余參數)
function sum(...numbers) {return numbers.reduce((acc, num) => acc + num, 0);
}window.onload=function (){let aLi = document.querySelectorAll('ul li');let arrLi = [...aLi];//可以把ul li轉變為數組arrLi.pop();arrLi.push('asfasdf');console.log(arrLi);
}function foo(a, b, ...rest) {console.log('a = ' + a);console.log('b = ' + b);console.log(rest);
}foo(1, 2, 3, 4, 5);
// 結果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]foo(1);
// 結果:
// a = 1
// b = undefined
// Array []let students = ['wangwu', 'zhangsan', 'lisi'];
let [s1, ...s2] = students; 
console.log(s1);  // 'wangwu' 
console.log(s2);  // ['zhangsan', 'lisi']//擴展運算符可以將數組或者對象轉為用逗號分隔的參數序列let ary = [1, 2, 3];...ary  // 1, 2, 3console.log(...ary);    // 1 2 3,相當于下面的代碼console.log(1,2,3);//擴展運算符可以應用于合并數組
// 方法一 let ary1 = [1, 2, 3];let ary2 = [3, 4, 5];let ary3 = [...ary1, ...ary2];// 方法二 ary1.push(...ary2);//將類數組或可遍歷對象轉換為真正的數組
let oDivs = document.getElementsByTagName('div'); 
oDivs = [...oDivs];

對象字面量增強

const name = 'Bob';
const person = {name,           // 屬性簡寫greet() { ... } // 方法簡寫//只是省略了 function 關鍵字和冒號 :,更清爽。
};

Symbol

  • 定義
    原本數據類型有 number、string、boolean、null、undefined,增加symbol
    Symbol 是一種新的原始數據類型,通常用于對象屬性的唯一標識,避免命名沖突。symbol不可以new,symbol()返回的是一個唯一值。
  • 作用
    用作對象屬性名,唯一性,防止屬性沖突
  • Symbol 如何作為對象屬性?
const key = Symbol('id');
const obj = { [key]: 123 };

Set 和 Map

Set 是一個無重復元素的集合,Map 是一個鍵值對集合(類似于Object)。

  • Set 與 Array 區別?去重?
特性ArraySet
是否允許重復值? 允許? 不允許
是否有順序? 有順序(按插入順序)? 有順序(按插入順序)
支持索引訪問? arr[0] 可訪問? 不支持 set[0] Set 沒有索引
數據結構有序列表唯一集合
是否可遍歷? 支持? 支持
去重能力? 需要手動處理? 自動去重
//set array互相轉換
const arr = [1, 2, 2, 3];
const unique = [...new Set(arr)]; // ? 數組去重
console.log(unique); // [1, 2, 3]const set = new Set([1, 2, 3]);
const backToArray = Array.from(set); // ? Set 轉數組
  • Map 與 Object 有何不同?
特性ObjectMap
鍵的類型支持只能是字符串或 Symbol任意類型(對象、函數、數字等)
是否有原型鏈有,默認繼承自 Object沒有原型,純凈鍵值對
鍵的順序無保障,按照插入順序可能亂? 按插入順序保存
獲取長度Object.keys().lengthmap.size
是否可迭代? 不能直接 for...of? 可直接 for...of
適合頻繁增刪? 效率低? 性能更優
是否用于 JSON 數據? 常用于結構化數據? 不能直接序列化
  • Map v.s. Set
    它們好多方法都一樣。除了set get
特性MapSet
結構鍵值對(key => value)值的集合(value)
是否唯一key 唯一所有值唯一
是否可迭代? 是(按插入順序)? 是(按插入順序)
常見用途存儲需要鍵值對的數據存儲去重的值
鍵的類型任意類型(對象、函數都行)值本身是唯一的,無鍵
方法set(), get(), has(), delete(), clear()add(), has(), delete(), clear()
const set = new Set([1, 2, 3, 3]);  // { 1, 2, 3 } 重復的只顯示一個
//set中的元素可以是任何可迭代對象 如數組、字符串、Map、Set
let str = "hello";
let set = new Set(str);
console.log(set);  // Set { 'h', 'e', 'l', 'o' }let map = new Map([["a", 1],["b", 2],["c", 3]
]);
let set = new Set(map);
console.log(set);  // Set { ['a', 1], ['b', 2], ['c', 3] }set.add(5);
set.delete(1);
set.has(2) //是否有這個值在set中 返回布爾值
set.size
set.clear()//清除所有成員 無返回值//Set 結構的實例與數組一樣,也擁有forEach方法,用于對每個成員執行某種操作,沒有返回值。
s.forEach(value => console.log(value))//set也有這些方法
for(let item of setArr){//默認就是valueconsole.log(item);
}
for(let item of setArr.keys()){console.log(item);}
for(let item of setArr.values()){}
for(let [k,v] of setArr.entries()){}let new_Set=[...set]//讓set轉為數組//類數組都有的特性 filter 是true的才留下
set = new Set([...set].filter(val=>val%2==0));//--------------
const map = new Map([['a', 1], ['b', 2]]);
const userMap = new Map();
userMap.set('name', 'Alice');
userMap.set('age', 30);
console.log(userMap.get('name')); // 'Alice'
console.log(userMap.has('age'));  // true
userMap.delete('age');
console.log(userMap.size);        // 1
userMap.clear();                  // 清空所有鍵值// 1. for...of
for (const [key, value] of map) {console.log(key, value);
}// 2. forEach
map.forEach((value, key) => {console.log(key, value);
});// 3. 獲取鍵、值、鍵值對
console.log([...map.keys()]);   // ['a', 'b']
console.log([...map.values()]); // [1, 2]
console.log([...map.entries()]); // [['a', 1], ['b', 2]]

Promise(異步編程)

Promise 是 ES6 引入的一種解決異步問題的方式,能夠更優雅地處理異步任務和錯誤。
Promise是一個構造函數,代表一個異步操作。調用.then(成功的回調函數,失敗的回調函數)方法時,成功的回調函數是必選的、失敗的回調函數是可選的。
如果上一個 .then() 方法中返回了一個新的 Promise 實例對象,則可以通過下一個 .then() 繼續進行處理。

  • 優點:
    解決了回調函數帶來的回調地獄問題。
    鏈式調用使得異步操作更加簡潔、可讀。
    提供了統一的錯誤處理機制(.catch())。
//回調地獄 嵌套多層
setTimeout(()=>{console.log('ok')setTimeout(()=>{console.log('ok')setTimeout(()=>{console.log('ok')//....continue...},3000)},2000)
},1000)
  • 缺點:比回調函數稍微復雜一些,需要一定的學習成本。
  • Promise 的三種狀態?
    pending(待定)、fulfilled(已完成)和 rejected(已拒絕)。
  • .then()、.catch()、.finally() 的執行順序?
    成功時.then()->finally()
    失敗時.catch()->finally()
    finally()始終最后執行
  • async/await 如何配合 Promise 使用?
    await所在的函數加async,await 后面必須是一個 Promise(或類 Promise 對象)
    try…catch 捕獲 Promise 的 reject
    async 函數本身也返回 Promise
function getError() {return new Promise((_, reject) => {setTimeout(() => reject('出錯了'), 1000);});
}async function fetchWithError() {try {const res = await getError();console.log(res);} catch (err) {console.error('捕獲錯誤:', err); // 輸出:捕獲錯誤: 出錯了}
}let a = 1;
let promise = new Promise(function(resolve, reject){
//將現有的東西,轉成一個promise對象,有resolve成功狀態;reject失敗狀態if(a==10){resolve('成功');}else{reject('失敗鳥');}
});
//promise.then(success, fail);
promise.then(res=>{console.log(res);
},err=>{     //err可以省略不寫 也可以改成catchconsole.log(err);
})
promise.then(res=>{console.log(res);
}).catch(err=>{  //reject,發生錯誤,別名console.log(err);
})
  • 批量處理promise
    Promise.all([p1, p2, p3]): 并行執行異步任務。把promise打包,扔到一個數組里面,打包完還是一個promise對象。必須確保,所有的promise對象,都是resolve狀態,都是成功狀態
    Promise.race([p1, p2, p3]): 只要有一個成功,就返回
let p1 = Promise.resolve('aaaa');
let p2 = Promise.resolve('bbbb');
let p3 = Promise.resolve('cccc');Promise.all([p1,p2,p3]).then(res=>{//console.log(res);let [res1, res2, res3] = res;console.log(res1, res2, res3);
})const promiseArr=[//數組中promise實例哪個先執行完 就返回哪個結果fs.readFile('./1.txt', 'utf8'),fs.readFile('./2.txt', 'utf8'),fs.readFile('./3.txt', 'utf8'),
]
Promise.race(promiseArr)
.then(res=>{console.log(res)
})
.catch(err=>{console.log(err.message)
})

類(class)和繼承

  • class 與構造函數的區別?
    相同點
    都可以創建實例對象;
    實例通過 new 創建;
    實例上的屬性是構造函數內部 this 定義的;
    共享方法都掛載在 prototype 上;
    都可以繼承(但 class 更方便);
對比點構造函數(Function)Class(類)
語法可讀性較低更清晰、接近傳統面向對象
原型方法定義手動掛載在 prototype 上自動添加到 prototype
嚴格模式默認非嚴格模式自動使用嚴格模式,不能被提升
構造函數調用可以不加 new(但會出錯)必須使用 new 調用
類體方法枚舉性自定義方法默認可枚舉類中方法默認不可枚舉
靜態方法需要手動掛載使用 static 定義更方便
類本身是語法糖,本質還是函數本質是 function
繼承借用 callObject.create使用 extends 更優雅
  • 構造函數首字母應當大寫,而普通函數首字母應當小寫,一些語法檢查工具如jslint將可以幫你檢測到漏寫的new
  • ES6 引入了面向對象編程的語法糖,使用 class 關鍵字來定義類,簡化了傳統的面向對象方法。class的定義包含了構造函數constructor,避免手動繼承(操作原型鏈)Student.prototype.hello = function () {…}這樣分散的代碼。
    JavaScript中,可以用關鍵字new來調用構造函數,并返回一個對象。它綁定的this指向新創建的對象,并默認返回this,也就是說,不需要在最后寫return this;用new 創建的對象還從原型上獲得了一個constructor屬性,它指向函數Student本身
xiaoming.constructor === Student.prototype.constructor; // true
Student.prototype.constructor === Student; // true
Object.getPrototypeOf(xiaoming) === Student.prototype; // true
xiaoming instanceof Student; // true
  • ES6 中的 class 是沒有提升功能的,而在 ES5 中,使用函數模擬的類是有“提升”效果的。即class 并沒有函數提升的特性,這意味著類聲明必須在使用之前聲明。如果在類 person 定義之前訪問它,會拋出 ReferenceError 錯誤。這是因為 ES6 的 class 聲明是 塊級作用域,并且沒有提升。
    在 ES5 中,我們通常使用構造函數來模擬類,而 JavaScript 中的函數聲明是有提升的(hoisting),也就是說函數聲明會被提升到作用域的頂部,所以我們可以在函數聲明之前調用它。
  • 靜態方法 在方法前面加static,不需要創建實例,直接調用類.類方法,class_name.static_func()
  • 繼承:新方法 子類extends父類
  //父類class Person{constructor(name){this.name = name;}showName(){return `名字為: ${this.name}`;}}//子類class Student extends Person{constructor(name,skill){//別忘了加上參數super(name);
//擴展子類而不是覆蓋對應函數時,必須super()把父類對應函數拉過來 this.skill = skill;}showSkill(){super.showSkill(); //父級的同名方法執行return  `哥們兒的技能為: ${this.skill}`;}}//調用let stu1 = new Student('Strive','逃學');console.log(stu1.showSkill());let a = 'strive';
let b = 'method';class Person {//ES6 class
//注意首字母大寫!!constructor(name, age) {this.name = name;this.age = age;}greet() {console.log(`Hello, I'm ${this.name}`);}
// 計算屬性名(computed property names)在 ES6 中動態創建對象的屬性或方法名。
//[a + b] 這種語法可以通過表達式來計算屬性名或方法名。[a + b]() {console.log("This is a dynamic method!");}//get 和 set 是用于定義**屬性訪問器(accessor properties)**的關鍵字。
//通過這兩個方法,可以自定義屬性的獲取(getter)和設置(setter)行為。
//Getter:用來獲取屬性的值。
//Setter:用來設置屬性的值。
/*
使用 getter 和 setter 的優點:
你可以在設置屬性時,加入額外的邏輯,例如數據驗證、格式化等。
獲取屬性時,你可以動態計算或處理值,而不需要暴露復雜的內部邏輯。
*/// Getter: 獲取_name的值,通過 person.name 的方式訪問,實際上調用的是 get name() 方法。get name() {return this._name;}// Setter: 設置_name的值,通過 person.name = 'newName' 的方式調用,實際上會觸發 set name(value) 方法set name(value) {if (value.length < 3) {console.log("Name must be at least 3 characters long.");} else {this._name = value;}}
}const p = new Person('Alice', 25);
p.greet();<script>function Person(name, age){//ES5 模擬類的函數this.name = name;this.age = age;}/* Person.prototype.showName = function(){return `名字為: ${this.name}`;};Person.prototype.showAge = function(){return `年齡為: ${this.age}`;}; */
//新舊版對比Object.assign(Person.prototype,{ //assign 合并showName(){return `名字為: ${this.name}`;},showAge(){return `年齡為: ${this.age}`;}});let p1 = new Person('Strive', 18);console.log(p1.showName());console.log(p1.showAge());//父類function Person(name){this.name = name;}Person.prototype.showName = function(){return `名字是: ${this.name}`;};//子類function Student(name,skill){Person.call(this,name); //繼承屬性  //使用矯正this函數this.skill = skill;}Student.prototype = new Person(); //繼承方法//調用let stu1 = new Student('Strive','逃學');console.log(stu1.showName());</script>

模塊化(ES Modules)

  • CommonJS 適用于服務器端的 Javascript 模塊化。nodejs默認支持CommonJS模塊化規范,如果想在nodejs中體驗ES6模塊化規范,需要按照以下步驟配置:確保安裝v14.15.1及+版本的nodejs,在package.json根節點中添加"type":"module"節點
  • ES Module v.s. CommonJS
    相同點:都是模塊化規范,導入導出模塊
    不同點:
    CommonJS出現在ES6前,不支持動態導入,運行時加載,同步加載模塊。導出的是值的拷貝,導入模塊執行完后模塊內部的變化不會影響外部。導出用module.exports or exports,導入用require。適用于服務端nodeJS。共享模塊內的變量。
    ES Module ES6引入,支持動態引入,編譯時加載,異步加載模塊。導出的是值的引用,外部和內部時刻保持一致變化。適用于瀏覽器。export and import。頂層this是undefined,在嚴格模式下運行,每個模塊有各自的頂層作用域,內部變量不會全局共享。有利于前端代碼拆分、懶加載優化性能、靜態分析Tree Shaking。
  • ES6模塊化規范
    ES6 模塊化規范是瀏覽器端與服務器端通用的模塊化開發規范。它的出現極大的降低了前端開發者的模塊化學習成本,開發者不需再額外學習 AMD、CMD 或 CommonJS 等模塊化規范。
    ES6 模塊化規范中定義:
    ? 每個 js 文件都是一個獨立的模塊
    ? 導入其它模塊成員使用 import 關鍵字
    有提升效果,import會自動提升到頂部,首先執行,也就是說:不管放前面放后面都最先引入
    無論導入多少次 都只導入一次
    ? 向外共享模塊成員使用 export 關鍵字
  1. 默認導出/導入
    注意:每個模塊只允許一次export default否則報錯
export default {n1,show
}//a.js
export function get_data(url){ //默認導出fetch(url).then(response => response.json()).then(data => {console.log(data);return data;});
}
//b.js
import { get_data } from './utils.js'; //默認導入
//同時要在b.html中模塊化的引入b.js//html
<script  type="module" src="./js/b.js"></script>
  1. 按需導出/導入
    每個模塊可以多次。
    按需導入時可用as重命名,可以和默認導入一起使用
// 按需導出
export const add = (a, b) => a + b;
export const a=12; //也可以導出變量
const b=1;
const c=2;
export {b as beta ,c as cici}
export function say(){}// 按需導入
import { add,a,cici } from './math.js';
  1. 如果是單純執行某個模塊代碼,不需要export,可以直接導入并執行即可。
// c.js
for(let i=0;i<3;i++)console.log(i)//index.js
import './c.js' //直接導入并執行
  1. html文件中如何引入?<script type="module"></script>+上述引入方式
<script type="module">import * as modTwo from './modules/2.js';console.log(modTwo.aaa);
</script>
  • import/export 和 require/module.exports 區別?
特性import/export(ES6)require/module.exports(CommonJS)
規范ES6(ECMAScript 2015)模塊化規范CommonJS 是 Node.js 模塊化規范
執行時機靜態分析(編譯時)動態加載(運行時)
是否支持異步加載支持異步加載(import()不支持(同步加載)
默認導入/導出使用 export default通過 module.exportsexports 導出
導入方式import {a, b} from './file'const {a, b} = require('./file')
動態導入支持動態導入(import()僅能使用 require 動態加載(但相對較麻煩)
運行時加載方式在文件編譯階段完成依賴關系在運行時逐步解析依賴
是否支持循環依賴支持(但會警告)支持(解決方案:require 返回緩存模塊)
是否會被提升不會,必須在頂部使用會提升,可以在文件任何位置使用
瀏覽器支持原生支持(需要模塊化支持的瀏覽器)需要通過構建工具(如 Webpack)支持
Node.js 版本支持Node.js 12+(需要開啟 "type": "module"默認支持
加載方式優化,支持 Tree Shaking每次執行都會重新加載模塊
  • export default 和 export 有什么不同?
特性export defaultexport (命名導出)
數量每個模塊只能有一個 default 導出每個模塊可以有多個命名導出
導入方式導入時可以自定義名字必須使用與導出時相同的名字
適用場景用于導出模塊的主要功能/類/對象等用于導出多個功能、常量、函數等
導入時的靈活性導入時名稱不受限制導入時名稱必須一致
動態導入適用于動態導入,便于重命名導入適用于動態導入,并保持一致性

迭代器與生成器(進階)

generator函數是‘生成器’,解決異步,深度嵌套的問題,現在有更好的解決方案: async/await

 function * gen(){yield 'welcome';//第一步yield 'to';//第二步return '牧碼人';//第三步}let g1 = gen();console.log(g1.next()); //{value: "welcome", done: false沒完成}console.log(g1.next()); //{value: "to", done: false}console.log(g1.next()); //{value: "牧碼人", done: true}console.log(g1.next());//{ value: undefined, done: true }for(let val of g1){console.log(val);//不會遍歷到return!
}//生成器可以解構賦值
let [a, ...b] = gen();//let[a.b.c]
//擴展運算符console.log(...gen());//轉換為數組
console.log(Array.from(gen()));//應用:請求
<script src="https://unpkg.com/axios/dist/axios.min.js"></script><script>//https://api.github.com/users/itstrivefunction * gen(){let val = yield 'aaa';yield axios.get(`https://api.github.com/users/${val}`);}let g1 = gen();let username = g1.next().value;//console.log(g1.next(username).value);g1.next(username).value.then(res=>{console.log(res.data);});</script>/*
整個流程沒有問題,
實際上你只是通過生成器來控制異步操作的執行順序(類似協程的模式)。
但是,生成器的部分在這里并沒有發揮出它的全部優勢。
通常生成器和異步操作結合的方式是通過 yield 來暫停執行,等待異步操作完成,
然后再繼續執行后續的代碼。你可以通過使用 async/await 來簡化代碼結構,
或者將生成器的控制交給一個專門的調度器。
*///改進
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>//https://api.github.com/users/itstrivefunction* gen() {let val = yield 'aaa';  // This is where we get the usernamelet response = yield axios.get(`https://api.github.com/users/${val}`);return response.data;//返回一個 Promise 對象}function handleGenerator(gen) {const iterator = gen();function iterate(result) {if (result.done) return;  // If done, stop//配合Promise.then()result.value.then(val => {iterate(iterator.next(val));  
// Pass the result to the next yield
//遞歸調用});}iterate(iterator.next());  
// Start the iteration}handleGenerator(gen);
</script>

可選鏈 & 空值合并運算符(ES2020+)

更方便地處理嵌套對象和可能為 null 或 undefined 的值。

  • 可選鏈(Optional Chaining)
    可選鏈(?.)是用來安全地訪問嵌套對象的屬性,它會自動判斷中間的任何一部分是否為 null 或 undefined,如果是,則會短路并返回 undefined,而不會拋出錯誤。
    user?.info?.nameuser->user.info->user.info.name
  • 空值合并運算符(Nullish Coalescing Operator)
    與 邏輯 OR 運算符 (||) 類似,但 ?? 僅在左側值為 null 或 undefined 時 才會返回右側值,而 || 會在左側值是任何假值(如 0, false, “”, NaN 等)時返回右側值。
  • 練習
    const name = user?.info?.name ?? 'default';

其他

?WeakSet

  • 定義
    WeakSet 是 ES6 引入的一種新的集合類型。
    弱引用:WeakSet 對象的元素是 弱引用,這意味著如果一個對象沒有其他引用指向它,垃圾回收機制會回收它,而不會因為它在 WeakSet 中的存在而阻止回收。
    WeakSet 支持以下基本操作:
    add(value):將一個對象添加到 WeakSet 中。如果該對象已經存在,什么都不做。初始往里面添加東西,是不行的。最好用add添加
    has(value):檢查某個對象是否在 WeakSet 中。如果存在返回 true,否則返回 false。
    delete(value):從 WeakSet 中刪除一個對象。如果該對象存在,
// 創建一些對象
let obj1 = {name: 'Alice'};
let obj2 = {name: 'Bob'};
let obj3 = {name: 'Charlie'};// 創建 WeakSet
let weakSet = new WeakSet();// 添加對象到 WeakSet
weakSet.add(obj1);
weakSet.add(obj2);// 檢查對象是否在 WeakSet 中
console.log(weakSet.has(obj1));  // true
console.log(weakSet.has(obj3));  // false// 刪除對象
weakSet.delete(obj1);
console.log(weakSet.has(obj1));  // false
  • 為什么會有weakset?
    1)跟蹤對象的存在性:WeakSet 可用于跟蹤對象是否曾經存在,而不阻止這些對象的垃圾回收。例如,某些需要動態管理的對象,且在不再需要時能被自動清除。
    2)避免內存泄漏:由于 WeakSet 使用弱引用,集合中的對象可以被垃圾回收,避免了因長期引用對象而導致的內存泄漏。???????在一些緩存系統中,可以使用 WeakSet 來存儲對象,確保不再被引用時自動被清除。
  • WeakSet 與 Set 的區別:
    在這里插入圖片描述

async/await

在此之前 promise只能通過鏈式.then()方式處理,可讀性不好,比較復雜。

  • async/await 是 ES8(ECMAScript 2017)引入的語法糖,旨在讓異步代碼更簡潔、更易讀。它是基于 Promise的,提供了更直觀的方式來處理異步操作,避免了傳統回調函數帶來的“回調地獄”(callback hell)。async/await 本質上 是寫法上看起來像同步,但底層仍是異步執行。async-await是配套使用的。在 async 方法中,第一個 await 之前的代碼會同步執行,await 之后的代碼會異步執行。
  • 雖然await寫法是一步一步的,但 await 后面的操作其實是非阻塞的,它只是讓當前 async 函數“暫停”,而不會阻塞整個程序的運行。你可以把 await 理解成一個“暫停點”,程序會在那兒等著 Promise 完成,然后繼續往下走。
    注意:await 是暫停,但不是“阻塞線程”
  • JavaScript 是 單線程的
    await 并不是開了一個新線程,而是把當前 async 函數掛起,等 Promise 完成后再“恢復”繼續執行;同時,主線程可以繼續處理其他任務(比如事件監聽、渲染頁面、執行其他函數等);類似于單核 CPU 的分時復用,這邊暫停下來,先去忙別的事,這邊ok了再繼續回來執行。
  • async 關鍵字
    async 用來標記一個函數為異步函數。當一個函數被標記為 async 時,它會返回一個 Promise對象。即使函數內部沒有顯式返回 Promise,async 函數會自動將返回值封裝在一個 Promise 對象中。
    當一個 async 函數中的 await 語句后面的 Promise 變成 reject(即發生錯誤)時,整個 async 函數會中斷執行,并且后續的代碼不會再被執行,除非你在 async 函數內使用了 try…catch 來捕獲錯誤。
  • await 關鍵字
    await 只能在 async 函數內使用,它會暫停函數的執行,等待一個 Promise 完成,并返回 Promise 的結果。如果 Promise 被拒絕,它會拋出異常,必須使用 try/catch 來捕獲錯誤。
    一旦 Promise 被解析,await 會返回解析值。如果 Promise 被拒絕,await 會拋出拒絕的錯誤。
    await后面可以是promise對象,也可以數字、字符串、布爾值等。
async function fetchData() {try {let response = await fetch("https://api.github.com/users/octocat");let data = await response.json();return data;} catch (error) {console.log("錯誤:", error);}
}
fetchData();  // 如果網絡請求失敗,輸出錯誤async function getUserRepos(username) {let userResponse = await fetch(`https://api.github.com/users/${username}`);let user = await userResponse.json();let reposResponse = await fetch(user.repos_url);let repos = await reposResponse.json();return repos;
}
getUserRepos("octocat").then((repos) => {console.log(repos);  // 輸出該用戶的所有倉庫
});

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/78503.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/78503.shtml
英文地址,請注明出處:http://en.pswp.cn/web/78503.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

初識 iOS 開發中的證書固定

引言 在移動應用安全領域&#xff0c;HTTPS/TLS 是數據傳輸的第一道防線&#xff0c;但僅依賴系統默認的證書驗證仍有被中間人&#xff08;MITM&#xff09;攻擊的風險。Certificate Pinning&#xff08;證書固定&#xff09;通過將客戶端信任“釘”在指定的服務器證書或公鑰上…

單片機的各個種類及其詳細介紹

一、按架構分類的深度解析 1. ARM Cortex-M系列 核心優勢&#xff1a; 統一架構&#xff1a;ARM生態完善&#xff0c;工具鏈&#xff08;Keil、IAR、GCC&#xff09;通用。 性能分層&#xff1a;M0&#xff08;低功耗&#xff09;、M3&#xff08;平衡&#xff09;、M4/M7&am…

5.7/Q1,GBD數據庫最新文章解讀

文章題目&#xff1a;Global, regional, and national burden and trends of rheumatoid arthritis among the elderly population: an analysis based on the 2021 Global Burden of Disease study DOI&#xff1a;10.3389/fimmu.2025.1547763 中文標題&#xff1a;全球、區域…

從微服務到AI服務:Nacos 3.0如何重構下一代動態治理體系?

在現代微服務架構的浪潮中&#xff0c;Nacos早已成為開發者手中的“瑞士軍刀”。作為阿里巴巴開源的核心中間件&#xff0c;它通過動態服務發現、統一配置管理和服務治理能力&#xff0c;為云原生應用提供了堅實的基石。從初創公司到全球500強企業&#xff0c;Nacos憑借其開箱即…

Unity與Unreal Engine(UE)的深度解析及高級用法

以下是Unity與Unreal Engine(UE)的深度解析及高級用法對比,結合技術特性、行業應用與未來發展進行綜合闡述: 一、核心差異與適用場景對比 1. 技術架構與編程模式 Unity 語言與腳本:主要使用C#,語法簡潔且易于學習,適合快速原型開發和中小型項目。支持可視化腳本工具(如…

李沐動手深度學習(pycharm中運行筆記)——05.線性代數

05.線性代數&#xff08;與課程對應&#xff09; 1、導入torch import torch2、 標量由只有一個元素的張量表示 x torch.tensor([3.0]) y torch.tensor([2.0]) print("x y:", x y, "\nx * y:", x * y, "\nx / y:", x / y, "\nx ** y…

Python3與Dubbo3.1通訊解決方案(dubbo-python)

【文章非VIP可讀&#xff0c;如果發現閱讀限制為系統自動修改閱讀權限&#xff0c;請留言我改回】 概述 最近AI項目需要java與python通訊&#xff0c;兩邊都是比較新的版本。因此需要雙方進行通訊&#xff0c;在這里記錄一下所采用的方案和關鍵點。 JAVA調用Python python通…

使用 DBeaver 將數據從 PostgreSQL 導出到 SQLite

使用 DBeaver 將數據從 PostgreSQL 導出到 SQLite&#xff0c;可按以下步驟進行&#xff1a; 1、連接到 PostgreSQL 數據庫&#xff1a;打開 DBeaver&#xff0c;點擊 “新建連接”&#xff0c;選擇 “PostgreSQL”&#xff0c;輸入數據庫的地址、端口、用戶名和密碼等信息&am…

介詞:連接名詞與句子其他成分的橋梁

文章目錄 1. with伴隨1.表示“跟人或物”的伴隨2.“行為”和“狀態”的伴隨2. of所屬關系1. 人或物的所屬關系2. 比較抽象的所屬關系3. in1. 在......中,在......范圍里2. 在某一段時間4. on1. 表示地點:在......上2. 表示時間:在某一天3. 關于某個主題5. at1. at + 具體時間…

FastApi快速實踐

文章目錄 一、主要功能&#xff1a;二、安裝 FastAPI 和 Uvicorn&#xff08;運行服務器&#xff09;三、示例代碼&#xff1a;四、運行服務器&#xff1a;1. 方式一&#xff1a;2. 方式二&#xff1a; 五、訪問接口六、如果需要跨域&#xff08;CORS&#xff09;七、總結 下面…

深度學習中保存最優模型的實踐與探索:以食物圖像分類為例

深度學習中保存最優模型的實踐與探索&#xff1a;以食物圖像分類為例 在深度學習的模型訓練過程中&#xff0c;訓練一個性能良好的模型往往需要耗費大量的時間和計算資源。而保存最優模型不僅可以避免重復訓練&#xff0c;還能方便后續使用和部署。本文將結合食物圖像分類的代…

護理崗位技能比賽主持稿串詞

男&#xff1a;尊敬的各位老師 女&#xff1a;親愛的各位同學 合&#xff1a;大家下午好。 男&#xff1a;在這鳥語花香&#xff0c;詩意盎然的季節里 女&#xff1a;在這陽光燦爛&#xff0c;激情似火的日子里 合&#xff1a;我們歡聚一堂&#xff0c;共同慶祝五一二國際護士節…

【翻譯、轉載】MCP 核心架構

核心架構 了解 MCP 如何連接客戶端、服務器和 LLM 模型上下文協議 (MCP) 構建在一個靈活、可擴展的架構之上&#xff0c;能夠實現 LLM 應用程序與集成之間的無縫通信。本文檔涵蓋了核心的架構組件和概念。 概述 MCP 遵循客戶端-服務器 (client-server) 架構&#xff0c;其中…

Python 數據智能實戰 (11):LLM如何解決模型可解釋性

寫在前面 —— 不只知其然,更要知其所以然:借助 LLM,揭開復雜模型決策的神秘面紗 在前面的篇章中,我們學習了如何利用 LLM 賦能用戶分群、購物籃分析、流失預測以及個性化內容生成。我們看到了 LLM 在理解數據、生成特征、提升模型效果和自動化內容方面的巨大潛力。 然而…

Linux:進程優先級及環境

一&#xff1a;孤兒進程 在Linux系統中&#xff0c;當一個進程創建了子進程后&#xff0c;如果父進程執行完畢或者提前退出而子進程還在運行&#xff0c;那么子進程就會成為孤兒進程。子進程就會被systemd&#xff08;系統&#xff09;進程收養&#xff0c;其pid為1 myproces…

Java大廠面試:Java技術棧中的核心知識點

Java技術棧中的核心知識點 第一輪提問&#xff1a;基礎概念與原理 技術總監&#xff1a;鄭薪苦&#xff0c;你對JVM內存模型了解多少&#xff1f;能簡單說說嗎&#xff1f;鄭薪苦&#xff1a;嗯……我記得JVM有堆、棧、方法區這些區域&#xff0c;堆是存放對象的地方&#xf…

CF1000E We Need More Bosses

CF1000E We Need More Bosses 題目描述 題目大意&#xff1a; 給定一個 n n n 個點 m m m 條邊的無向圖&#xff0c;保證圖連通。找到兩個點 s , t s,t s,t&#xff0c;使得 s s s到 t t t必須經過的邊最多&#xff08;一條邊無論走哪條路線都經過ta&#xff0c;這條邊就是…

imx6uLL應用-v4l2

Linux V4L2 視頻采集 JPEG 解碼 LCD 顯示實踐 本文記錄一個完整的嵌入式視頻處理項目&#xff1a;使用 V4L2 接口從攝像頭采集 MJPEG 圖像&#xff0c;使用 libjpeg 解碼為 RGB 格式&#xff0c;并通過 framebuffer 顯示在 LCD 屏幕上。適用于使用 ARM Cortex-A 系列開發板進…

強化學習機器人模擬器——QAgent:一個支持多種強化學習算法的 Python 實現

QAgent 是一個靈活的 Python 類,專為實現經典的強化學習(Reinforcement Learning, RL)算法而設計,支持 Q-learning、SARSA 和 SARSA(λ) 三種算法。本篇博客將基于提供的 q_agent.py 代碼,詳細介紹 QAgent 類的功能、結構和使用方法,幫助您理解其在強化學習任務中的應用,…

Feign的原理

為什么 SpringCloud 中的Feign&#xff0c;可以幫助我們像使用本地接口一樣調用遠程 HTTP服務&#xff1f; Feign底層是如何實現的&#xff1f;這篇文章&#xff0c;我們一起來聊一聊。 1. Feign 的基本原理 Feign 的核心思想是通過接口和注解定義 HTTP 請求&#xff0c;將接…