一、作用域
提到作用域(作用域又分為局部作用域和全局作用域),就要想到變量。因為作用域規定了變量能夠被訪問的范圍(也就是作用域是為變量而服務的),為了避免全局變量污染這一情況,所以需要使用閉包函數創建隔離作用域。
這就是接下來我們要將作用域、作用域鏈、閉包,與變量聯系起來的思路。
1.1 局部作用域
首先局部作用域分為函數作用域和塊作用域。
函數作用域
函數作用域:就是在函數內部聲明的變量在函數外部不能使用
function fn (e) {const i = 3console.log(i)console.log(e)}fn(4)//在函數外部會報錯console.log(`這是${i}`)console.log(`這是${e}`)
塊作用域
{ } 大花括號中的就是塊作用域 比如if語句 for循環等
在塊作用域中,代碼塊內部聲明的變量外部將【有可能】無法被訪問==》為什么是有可能===》因為如果是var變量,它不講塊作用域,所以外部可以訪問====》但是如果是let或者const變量,外部就不可以被訪問
for (var i = 1; i <= 3; i++) {console.log(i)}console.log(i)for (let j = 1; j <= 3; j++) {console.log(j)}console.log(j)
- let 聲明的變量會產生塊作用域,var 不會產生塊作用域
- const 聲明的常量也會產生塊作用域
- 不同代碼塊之間的變量無法互相訪問
- 推薦使用 let 或 const
1.2 全局作用域
顧名思義,就是script標簽和.js文件的最外層就是所謂的全局作用域,在這里定義的變量在函數內部可以被訪問,函數內部就上上文講的局部作用域。
盡量少使用,避免變量污染。所謂的變量污染,大家可以理解為例如有個變量,它正在配合一個任務按部就班地進行著(也就是下面的例子,調用一次函數,count++一次),忽然有一天,因為它是全局變量,別人給他更改了一個很大值,這時候原先的任務還在執行,調用結果就是在別人給他更改的值的基礎上的++,這也就說明不能正常配合任務執行了,======》輕易地導致了全局變量的污染!
// count是全局變量 很容易被修改let count = 1function fn2 () {count++console.log(`函數被調用了${count}次`)}fn2()
1.3 作用域鏈
本質上是底層的變量查找機制
也就是函數被執行時,優先從當前函數作用域中查找變量;如果當前作用域查找不到會一次逐級查找父級作用域知道全局作用域。
總結來說就是嵌套關系的作用域串聯起來形成了作用域,相同作用域鏈中按著從小到大的規則查找變量;子作用域能夠訪問父作用域,父作用域無法訪問子作用域(中的變量)。
1.4 垃圾回收機制 (這部分待完善)
JS中內存的分配和回收都是自動完成的,內存在不使用的時候會被垃圾回收器自動回收。
正因為垃圾回收器的存在,所以大家在寫JS不太注意內存管理的問題
但如果不了解JS的內存管理機制,我們同樣非常容易成內存泄漏(內存無法被回收)的情況,所謂的內存泄漏就是:
不再用到的內存,沒有及時釋放
JS環境中分配的內存, 一般有如下生命周期:
- 內存分配:當我們聲明變量、函數、對象的時候,系統會自動為他們分配內存
- 內存使用:即讀寫內存,也就是使用變量、函數等
- 內存回收:使用完畢,由垃圾回收自動回收不再使用的內存
- 說明:
全局變量一般不會回收(關閉頁面回收);
一般情況下局部變量的值, 不用了, 會被自動回收掉
1.5 閉包
閉包 = 內層函數 + 外層函數的變量
兩種表達方式:
function outer () {// 閉包 = 內層函數 + 外層函數的變量let a = 10表達方式一:// function fn () {/ / console.log(a)/ /}// return一個函數 就可以使用閉包了//return fn表達方式二:因為fn===function fn() 也就是return直接指向了function函數return function fn () {console.log(a)}return }// outer()===fn===function fn()const fun = outer()fun()
利用閉包思想,來避免全部變量受污染的情況 最好的方法就是不使用全局變量
<script>// count是全局變量 很容易被修改// let count = 1// function fn2 () {// count++// console.log(`函數被調用了${count}次`)// }// fn2()// 閉包應用:內部聲明變量,實現數據的私有function fn () {let count = 1function fun () {count++console.log(`函數被調用${count}次`)}return fun}const result = fn()result()</script>
二、預解析(了解)
2.1 變量提升 var
<script>// var的變量提升// 所謂的變量提升就是當前變量在下面,上面使用的時候,就把所有var聲明的變量提升到當前作用域的最前面// 只提升聲明 不提升賦值// undefined 表示聲明變量未給值// console.log(num + '件')// var num = 10// console.log(num + '件');function fn () {console.log(num)var num = 10// 相當于 var num// console.log(num)// num=10}fn()</script>
2.2 函數提升
建議:使用let或者const,遵循先聲明后使用
<script>// 1.會把所有函數聲明提升到當前作用域的前面// 2.提升函數聲明 不提升函數調用fn()function fn () {console.log('函數提升')}// 函數表達式 必須先聲明和賦值 后調用 否則報錯fun()var fun = function () {console.log('函數表達式')}// 因為上面這句話是使用var定義的,根據var的變量提升,所以會有// var fun// fun()// function() {// console.log('函數表達式')// } 不可能實現聲明里面沒賦值就可以調用</script>
二、箭頭函數
2.1 動態參數
- arguments 是一個偽數組(具有length和索引號,但是它不具有數組的push(), pop(), forEach(), map(), filter() 等方法。),只存在于函數中
- arguments 的作用是動態獲取函數的實參
- 因為具有length和索引號,所以可以通過for循環依次得到傳遞過來的實參
- arguments的好處就是當我們傳入的實參數量不固定時,也就是一會求兩個數的和,一會求三個、四個…此時形參就是不固定的 此時使用arguments就非常好用 如下案例:
<script>// 每一個函數里面默認都有一個動態參數arguments作為形參,所以不用特別將arguments寫進形參中// function getSum () {// console.log(arguments)// }// getSum(2, 5, 56)function getSum () {let sum = 0// arguments動態參數 只存在于函數里面for (let i = 0; i < arguments.length; i++) {sum += arguments[i]}console.log(sum)}getSum(2, 34, 5, 67, 3)</script>
2.2 this問題
查找this的方法:從當前作用域查找,如果查找不到 就按照作用域鏈來查找
案例一:最簡單的函數調用中,this的指向問題
在這里有一個誤區,因為是fn調用的,所以this指向fn 注意:fn()是函數的定義,不是調用者。fn()在調用時,全寫為 window.fn(),所以調用者是window
function fn () {console.log(this)}fn()
案例二:不要看到{},就認為是作用域
不要看到{},就認為是作用域,這樣會誤認為obj是函數的調用者,作用域是由函數和塊級語句創建的。我們判定作用域就是如果不是函數也不是塊級語句,+含有{},就不是作用域。
案例:指向的是函數的調用者=>對象
const obj = {name: 'andy',sayHi: function () {console.log(this)//指向的是函數的調用者=>對象}}obj.sayHi()
案例三:全局作用域 指向window
// 全局作用域 指向windowconst obj1 = {uname: 'Pink老師',sayHi: () => {console.log(this)}}obj1.sayHi()
案例四:函數里面套箭頭函數,指向obj2
因為箭頭函數中沒有this 所以往上一層找 通過上一層的函數指向了函數的調用者obj2
// 指向objconst obj2 = {uname: 'pink老師',sayHi: function () {let i = 10const count = () => {console.log(this)}count()}}obj2.sayHi()
剩余與展開
剩余參數的定義是 . . .數組名 是一個真數組 與arguments異曲同工
function getSum (...arr) {// console.log(arr)let sum = 0for (let i = 0; i < arr.length; i++) {sum += arr[i]}console.log(sum)}getSum(1, 2, 3)
但是,因為arguments需要在函數里面,這就帶來一些不方便,所以…arr,它可以實現求最值,合并數組等功能。
<script>// const arr = [1, 2, 3]// console.log(...arr);// console.log(Math.max(...arr)) //里面放的只能是字符 不能是數字// 合并數組const arr1 = [1, 2, 3]const arr2 = [3, 4, 5]const arr3 = [...arr1, ...arr2]console.log(arr3);</script>
剩余參數的另一種應用
從前到后,形參和實參一一對應,但是如果實參過于多,后面的統一由剩余參數接收
<script>function getSum (a, b, ...arr) {console.log(arr) // 使用的時候不需要寫 ...}getSum(2, 3)getSum(1, 2, 3, 4, 5)</script>
2.3 箭頭函數
基本語法
<script>// const fn = function () {// console.log(123)// }// fn()// 1.箭頭函數基本語法// const fn = () => {// console.log(123)// }// fn()// const fn = (x) => {// console.log(x)// }// fn(1)// 2.只有一個形參的時候 可以省略小括號// const fn = x => {// console.log(x)// }// fn(1)// 3.只有一行代碼的時候 可以省略大括號// const fn = x => console.log(x)// fn(1)// 4.只有一行代碼的時候 可以直接省略return// const fn = x => x + x// console.log(fn(1))// 5.箭頭函數可以直接返回個對象 將大括號轉化為小括號const fn = uname => ({ uname: uname })console.log(fn('劉德華'));</script>
使用箭頭函數求和
<script>//箭頭函數中沒有arguments參數, 并且實參中傳入的是字符,可以通過...轉化為數組 很方便地實現數組中國數據的迭代const getSum = (...arr) => {let sum = 0for (let i = 0; i < arr.length; i++) {sum += arr[i]}return sum}const result = getSum(2, 3, 4)console.log(result);</script>
<script>// 以前this的指向 誰調用的這個函數 this就指向誰// console.log(this)// function fn () {// console.log(this)// }// window.fn()const obj = {name: 'anfy',sayHi: function () {console.log(this) //指向的是對象}}obj.sayHi()const obj1 = {uname: 'pink老師',sayHi: () => {console.log(this)// this指向window 因為箭頭函數中沒有this 所以要去window中找}}obj1.sayHi()// 當前區域沒有this 按照作用域鏈往上一層找 函數里面有thisconst obj2 = {uname: 'pink老師',sayHi: function () {let i = 10const count = () => {console.log(this)}count()}}obj2.sayHi()btn.addEventListener('click', () => {console.log(this)})</script>
這里我有一個困擾 不知道大家有沒有 就是我在糾結 btn.addEventListener(‘click’, () => {
console.log(this)
}) 我想的是箭頭函數沒有this 它可以跑到外層 外層就是add 不就可以指向函數的調用者了嗎addEventListener 本身并不是一個作用域(scope),而是一個方法(method)。作用域是 JavaScript 中變量和函數可訪問性的區域。主要由函數和代碼塊(如 { ... })創建。既然箭頭函數中沒有this 往外走到父級作用域 所以也就來到了全局作用域 全局作用域指向windowaddEventListener 的回調中,外層上下文并不是 addEventListener 函數本身,而是定義箭頭函數的那個作用域。 箭頭函數被定義在一個全局作用域或模塊作用域中
<script>// 1.以前this的指向 誰調用的這個函數 this就指向誰// console.log(this)// function fn () {// console.log(this)// }// window.fn() //===fn()const obj = {name: 'anfy',sayHi: function () {console.log(this) //指向的是函數的調用者,也就是對象}}obj.sayHi()const obj1 = {uname: 'pink老師',sayHi: () => {console.log(this)// this指向window 因為箭頭函數中沒有this 所以要去window中找}}obj1.sayHi()// 當前區域沒有this 按照作用域鏈往上一層找 函數里面有thisconst obj2 = {uname: 'pink老師',sayHi: function () {let i = 10const count = () => {console.log(this)}count()}}obj2.sayHi()btn.addEventListener('click', () => {console.log(this)})</script>
三、 解構賦值
解構賦值是一種快速為變量賦值的簡潔語法,本質上仍然是為變量賦值
分為:數組解構
對象解構
3.1 數組解構
數組解構是將數組的單元值快速批量賦值給一系列變量的簡潔語法.
基本語法:
1.左側的[ ]用于聲明變量因為是多個,所以是批量聲明變量,右側數組的單元值將被賦值給左側的變量中。
2.變量的順序對應數組單元值的位置依次進行賦值操作。
// 數組解構 賦值const arr = [100, 60, 80]// const [max, min, avg] = arrconst [max, min, avg] = [100, 60, 80]console.log(max)console.log(min)console.log(avg)// 交換兩個變量的值let a = 1let b = 2;[b, a] = [a, b]console.log(a, b);
必須加分號的兩種情況:
// 1.立即執行函數要加分號(function () { })();(function () { })()// 2.使用數組的時候const arr = [1, 2, 3]const str = 'pink'// 真正數組前面要加上分號;[1, 2, 3].map(function (item) {console.log(item)})// 數組名不用加上分號// arr.map(function (item) {// console.log(item)// })
數組解構的一些細節:
// 1.變量多 單元值少 undefined// const [a, b, c, d] = [1, 2, 3]// console.log(a)// console.log(b)// console.log(c)// console.log(d)// 2.變量少 單元值多const [e, f] = [1, 2, 3]console.log(e)console.log(f)// 3.剩余參數 變量少 單元制多const [g, h, ...i] = [1, 2, 3, 4]console.log(g)console.log(h)console.log(i)// 4.防止有undefined傳單元值 設置默認值// const [a = 0, b = 0] = []// console.log(a)// console.log(b)// const [c = '手機', d = '華為'] = ['小米']// console.log(c)// console.log(d)// 5.按需導入 忽略返回值 以逗號隔開// const [a, b, , d] = [1, 2, 3, 4]// console.log(a)// console.log(b)// console.log(d)// 6.支持多維數組結構// 一般的多維數組// const arr = [1, 2, [3, 4]] //二維// console.log(arr[0])// console.log(arr[1])// console.log(arr[2][0]);// 數組解構const [a, b, [c, d]] = [1, 2, [3, 4]] //二維console.log(a)console.log(b)console.log(c)console.log(d);
3.2 對象解構
對象解構是將對象屬性和方法快速批量賦值給一系列變量的簡潔語法
對象解構的幾種情況:
<script>// 1.對象解構// const obj = {// // 對象里面為屬性 對象外面的為變量// uname: 'pink老師',// age: 18// }// 2.解構的語法 變量名字 屬性名字相同 // const { uname, age } = {// // 對象里面為屬性// uname: 'pink老師',// age: 18// }// console.log(uname)// console.log(age)// 3.對象解構的變量名 可以重新改名 舊變量名:新變量名// const { uname: username, age } = { uname: 'pink老師', age: 18 }// console.log(username)// console.log(age);// 4.數組對象解構const pig = [{uname: '佩奇',age: 18}]const [{ uname, age }] = pigconsole.log(uname);</script>
多級對象解構
// 多級對象解構 也就是對象里面套對象const pig = {name: '佩奇',family: {mother: '豬媽媽',father: '豬爸爸',sister: '喬治'},age: 7}const { name, family: { mother, father, sister } } = pigconsole.log(name)console.log(mother)console.log(father)console.log(sister);
對象解構綜合案例
<script>// 1. 這是后臺傳遞過來的數據const msg = {"code": 200,"msg": "獲取新聞列表成功","data": [{"id": 1,"title": "5G商用自己,三大運用商收入下降","count": 58},{"id": 2,"title": "國際媒體頭條速覽","count": 56},{"id": 3,"title": "烏克蘭和俄羅斯持續沖突","count": 1669},]}// 需求一,將以上msg對象 采用對象解構的方式 只選出data數據使用來作為渲染頁面的數據// const { data } = msg// console.log(data)// 需求2: 上面msg是后臺傳遞過來的數據,我們需要把data選出當做參數傳遞給 函數// msg雖然很多屬性 但是我們利用解構只要data值// const { data } = msg// 所以這個{}相當于在說要對那個對象進行對象解構function render ({ data }) {// const { data } = arrconsole.log(data)}render(msg)// 需求3, 為了防止msg里面的data名字混淆,要求渲染函數里面的數據名改為 myDatafunction render ({ data: myData }) {console.log(myData)}render(msg)</script>
forEach方法
<script>const arr = ['red', 'green', 'pink']// item是必須要寫的 // foreach就是純遍歷 加強版的for循環 適合于遍歷數組對象const result = arr.forEach(function (item, index) {console.log(item)//每個數組元素console.log(index)//索引號})console.log(result)//不返回值</script>
綜合案例
綜合案例一:
小熱身,先講一個結合forEach方法小案例:
首先這個案例其實就是頁面已經設計好了,只要我們拿到數據,渲染到頁面就行了,下面的item就是需要填寫的數據,這些數據如果沒有js,我們填入的都是死的數據,現在有了js,數據就變成活得了,將獲得的數據填寫在item中,然后將item追加到list大頁面中。又下面的item都是字符串,所以我們采用字符串拼接,最后追加到list中。

***完整代碼 我貼在最后了***
```javascript//1.聲明一個字符串變量let str = ''// 2.遍歷數據,遍歷8次goodsList.forEach(item => {// console.log(item)const { id } = item// 對象解構const { name, price, picture } = item//字符串str += `<div class="item"><img src=${picture} alt=""><p class="name">${name}</p><p class="price">${price}</p></div>`})//最后追加document.querySelector('.list').innerHTML = str
filter 篩選數組 返回的是真數組
<script>const arr = [10, 20, 30]// const newArr = arr.filter(function (item, index) {// // 也有用item和index// // console.log(item)// // console.log(index)// return item >= 20// })// console.log(newArr);// 寫成箭頭函數const newArr = arr.filter(item => item >= 20)console.log(newArr);</script>
綜合案例二、渲染函數——篩選(filter)
完整代碼見 ## 完整代碼2
// 1.渲染函數 封裝function render (arr) {//聲明空字符串let str = ''//遍歷數組arr.forEach(item => {// 解構const { name, picture, price } = itemstr += `<div class="item"><img src=${picture} alt=""><p class="name">${name}</p><p class="price">${price}</p></div>`})//追加給listdocument.querySelector('.list').innerHTML = str}render(goodsList)//頁面一打開就需要渲染// 2.過濾篩選document.querySelector('.filter').addEventListener('click', e => {const { tagName, dataset } = e.target//判斷if (tagName === 'A') {let arr = goodsListif (dataset.index === '1') {arr = goodsList.filter(item => item.price > 0 && item.price <= 100)} else if (dataset.index === '2') {arr = goodsList.filter(item => item.price >= 100 && item.price <= 300)} else if (dataset.index === '3') {arr = goodsList.filter(item => item.price >= 300)}//渲染函數render(arr)}})
完整代碼1
<!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>商品渲染</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}.list {width: 990px;margin: 0 auto;display: flex;flex-wrap: wrap;padding-top: 100px;}.item {width: 240px;margin-left: 10px;padding: 20px 30px;transition: all .5s;margin-bottom: 20px;}.item:nth-child(4n) {margin-left: 0;}.item:hover {box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);transform: translate3d(0, -4px, 0);cursor: pointer;}.item img {width: 100%;}.item .name {font-size: 18px;margin-bottom: 10px;color: #666;}.item .price {font-size: 22px;color: firebrick;}.item .price::before {content: "¥";font-size: 14px;}</style>
</head><body><div class="list"><!-- <div class="item"><img src="" alt=""><p class="name"></p><p class="price"></p></div> --></div><script>const goodsList = [{id: '4001172',name: '稱心如意手搖咖啡磨豆機咖啡豆研磨機',price: '289.00',picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',},{id: '4001594',name: '日式黑陶功夫茶組雙側把茶具禮盒裝',price: '288.00',picture: 'https://yanxuan-item.nosdn.127.net/3346b7b92f9563c7a7e24c7ead883f18.jpg',},{id: '4001009',name: '竹制干泡茶盤正方形瀝水茶臺品茶盤',price: '109.00',picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',},{id: '4001874',name: '古法溫酒汝瓷酒具套裝白酒杯蓮花溫酒器',price: '488.00',picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',},{id: '4001649',name: '大師監制龍泉青瓷茶葉罐',price: '139.00',picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',},{id: '3997185',name: '與眾不同的口感汝瓷白酒杯套組1壺4杯',price: '108.00',picture: 'https://yanxuan-item.nosdn.127.net/8e21c794dfd3a4e8573273ddae50bce2.jpg',},{id: '3997403',name: '手工吹制更厚實白酒杯壺套裝6壺6杯',price: '99.00',picture: 'https://yanxuan-item.nosdn.127.net/af2371a65f60bce152a61fc22745ff3f.jpg',},{id: '3998274',name: '德國百年工藝高端水晶玻璃紅酒杯2支裝',price: '139.00',picture: 'https://yanxuan-item.nosdn.127.net/8896b897b3ec6639bbd1134d66b9715c.jpg',},]//1.聲明一個字符串變量let str = ''// 2.遍歷數據,遍歷8次goodsList.forEach(item => {// console.log(item)const { id } = item// 對象解構const { name, price, picture } = item//字符串str += `<div class="item"><img src=${picture} alt=""><p class="name">${name}</p><p class="price">${price}</p></div>`})//最后追加document.querySelector('.list').innerHTML = str</script>
</body></html>
完整代碼2
<!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>商品渲染</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}.list {width: 990px;margin: 0 auto;display: flex;flex-wrap: wrap;}.item {width: 240px;margin-left: 10px;padding: 20px 30px;transition: all .5s;margin-bottom: 20px;}.item:nth-child(4n) {margin-left: 0;}.item:hover {box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);transform: translate3d(0, -4px, 0);cursor: pointer;}.item img {width: 100%;}.item .name {font-size: 18px;margin-bottom: 10px;color: #666;}.item .price {font-size: 22px;color: firebrick;}.item .price::before {content: "¥";font-size: 14px;}.filter {display: flex;width: 990px;margin: 0 auto;padding: 50px 30px;}.filter a {padding: 10px 20px;background: #f5f5f5;color: #666;text-decoration: none;margin-right: 20px;}.filter a:active,.filter a:focus {background: #05943c;color: #fff;}</style>
</head><body><div class="filter"><a data-index="1" href="javascript:;">0-100元</a><a data-index="2" href="javascript:;">100-300元</a><a data-index="3" href="javascript:;">300元以上</a><a href="javascript:;">全部區間</a></div><div class="list"><!-- <div class="item"><img src="" alt=""><p class="name"></p><p class="price"></p></div> --></div><script>const goodsList = [{id: '4001172',name: '稱心如意手搖咖啡磨豆機咖啡豆研磨機',price: '289.00',picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',},{id: '4001594',name: '日式黑陶功夫茶組雙側把茶具禮盒裝',price: '288.00',picture: 'https://yanxuan-item.nosdn.127.net/3346b7b92f9563c7a7e24c7ead883f18.jpg',},{id: '4001009',name: '竹制干泡茶盤正方形瀝水茶臺品茶盤',price: '109.00',picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',},{id: '4001874',name: '古法溫酒汝瓷酒具套裝白酒杯蓮花溫酒器',price: '488.00',picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',},{id: '4001649',name: '大師監制龍泉青瓷茶葉罐',price: '139.00',picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',},{id: '3997185',name: '與眾不同的口感汝瓷白酒杯套組1壺4杯',price: '108.00',picture: 'https://yanxuan-item.nosdn.127.net/8e21c794dfd3a4e8573273ddae50bce2.jpg',},{id: '3997403',name: '手工吹制更厚實白酒杯壺套裝6壺6杯',price: '99.00',picture: 'https://yanxuan-item.nosdn.127.net/af2371a65f60bce152a61fc22745ff3f.jpg',},{id: '3998274',name: '德國百年工藝高端水晶玻璃紅酒杯2支裝',price: '139.00',picture: 'https://yanxuan-item.nosdn.127.net/8896b897b3ec6639bbd1134d66b9715c.jpg',},]// 1.渲染函數 封裝function render (arr) {//聲明空字符串let str = ''//遍歷數組arr.forEach(item => {// 解構const { name, picture, price } = itemstr += `<div class="item"><img src=${picture} alt=""><p class="name">${name}</p><p class="price">${price}</p></div>`})//追加給listdocument.querySelector('.list').innerHTML = str}render(goodsList)//頁面一打開就需要渲染// 2.過濾篩選document.querySelector('.filter').addEventListener('click', e => {const { tagName, dataset } = e.target//判斷if (tagName === 'A') {let arr = goodsListif (dataset.index === '1') {arr = goodsList.filter(item => item.price > 0 && item.price <= 100)} else if (dataset.index === '2') {arr = goodsList.filter(item => item.price >= 100 && item.price <= 300)} else if (dataset.index === '3') {arr = goodsList.filter(item => item.price >= 300)}//渲染函數render(arr)}})</script>
</body></html>