四天学会JS高阶(学好vue的关键)——作用域解构箭头函数(理论+实战)(第一天)

一、作用域

提到作用域(作用域又分为局部作用域和全局作用域),就要想到变量。因为作用域规定了变量能够被访问的范围(也就是作用域是为变量而服务的),为了避免全局变量污染这一情况,所以需要使用闭包函数创建隔离作用域。
这就是接下来我们要将作用域、作用域链、闭包,与变量联系起来的思路。

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)
  1. let 声明的变量会产生块作用域,var 不会产生块作用域
  2. const 声明的常量也会产生块作用域
  3. 不同代码块之间的变量无法互相访问
  4. 推荐使用 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. 内存分配:当我们声明变量、函数、对象的时候,系统会自动为他们分配内存
  2. 内存使用:即读写内存,也就是使用变量、函数等
  3. 内存回收:使用完毕,由垃圾回收自动回收不再使用的内存
  4. 说明:
    全局变量一般不会回收(关闭页面回收);
    一般情况下局部变量的值, 不用了, 会被自动回收掉

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 动态参数

  1. arguments 是一个伪数组(具有length和索引号,但是它不具有数组的push(), pop(), forEach(), map(), filter() 等方法。),只存在于函数中
  2. arguments 的作用是动态获取函数的实参
  3. 因为具有length和索引号,所以可以通过for循环依次得到传递过来的实参
  4. 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中。
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/8aad29cd731a4d18903cda7d7f5609d0.png)
***完整代码 我贴在最后了***
```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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/12315.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何排查域名网站无法访问了页面报500错误

本周有一个客户&#xff0c;购买Hostease的虚拟主机&#xff0c;询问我们的在线客服&#xff0c;域名网站无法访问了报500错误页面&#xff0c;怎么办&#xff1f;我们为用户提供相关教程&#xff0c;用户很快解决了遇到的问题。在此&#xff0c;我们分享这个操作教程&#xff…

bugfix:遇见“隐形字符”:ⅰ与i的编码迷局

前言 在软件开发的世界里&#xff0c;遇到各种奇奇怪怪的bug是在所难免的。今天&#xff0c;我就遭遇了一个看似简单实则棘手的问题——用户反馈账号无法登录&#xff0c;系统一直提示“账号不存在”。一番抽丝剥茧后&#xff0c;我发现问题竟然出在一个不起眼的字符上&#x…

Go微服务: Gin框架搭建网关, 接入熔断器,链路追踪以及服务端接入限流和链路追踪

概述 本文使用最简单和快速的方式基于Gin框架搭建一个微服务的网关调用微服务的场景网关作为客户端基于RPC调用某一服务端的服务并接入熔断和限流以及链路追踪具体场景&#xff1a;通过网关API查询购物车里的数据在最后&#xff0c;会贴上网关和购物车服务的代码仓库 服务端搭…

避雷:搭建AI知识库注意事项

AI知识库作为信息存储和进行智能处理的核心部分&#xff0c;受到越来越多企业的重视。为了更好地发展&#xff0c;企业也纷纷开始搭建AI知识库。然而&#xff0c;在搭建AI知识库的过程中&#xff0c;也有很多雷区容易踩到&#xff0c;导致项目延迟、效果不佳甚至失败。所以&…

《控制系统实验与综合设计》计控第三次(含程序和题目)

实验七 采样控制系统的分析 一、实验完成任务 1、熟悉用 LF398 组成的采样控制系统&#xff1b; 2、通过本实验理解采样定理和零阶保持器的原理及其实现方法&#xff1b; 3、观察系统在阶跃作用下的稳态误差。 4.、研究开环增益 K 和采样周期 T 的变化对系统动态性能的影响…

Linux基础之进程-进程状态

目录 一、进程状态 1.1 什么是进程状态 1.2 运行状态 1.2 阻塞状态 1.3 挂起状态 二、Linux操作系统上具体的进程状态 2.1 状态 2.2 R 和 S 状态的查看 2.3 后台进程和前台进程 2.4 休眠状态和深度休眠状态 一、进程状态 1.1 什么是进程状态 首先我们知道我们的操作系…

分布式光伏监控系统功能模块详解

目前&#xff0c;分布式光伏发电系统的总容量比较小&#xff0c;并且光伏电站的功率受外界环境影响容易出现大起大落的现象。这使电压调整变得很困难。光伏电站运行维护人员不足&#xff0c;长时间不保养维护会影响光伏电站的发电效率。针对上述问题&#xff0c;鹧鸪云基于无线…

天锐绿盾|设计院图纸透明加密软件、制造业文件资料防止外泄

#图纸加密软件# 天锐绿盾是一家专注于数据安全解决方案的提供商&#xff0c;其产品主要为企业级用户设计&#xff0c;旨在保护敏感信息和知识产权免遭未经授权的访问或泄露。"天锐绿盾"的图纸透明加密软件和机械制造业文件资料防止外泄系统&#xff0c;是专为设计院…

JS中的宏任务和微任务

JavaScript 引擎是建立在一个事件循环系统之上的&#xff0c;它实时监控事件队列&#xff0c;如果有事件就执行&#xff0c;如果没有事件就等待。事件系统是一个典型的生产消费模式&#xff0c;生产者发出事件&#xff0c;接收者监听事件&#xff0c;在UI 开发中是常见的一个设…

Modbus TCP转CAN网关在不同行业中的应用以及其使用上的优势

倍讯科技Modbus TCP转CAN网关通常被用于工业自动化领域&#xff0c;特别是在需要连接现有Modbus TCP网络和CAN总线设备的场景中。以下是该网关在不同行业中的应用以及其使用上的优势&#xff1a; 1. 制造业&#xff1a; - 在制造业中&#xff0c;各种类型的设备和机器通常使用不…

Java项目实现报文数据校验注解方式(必输项、值大小)

普通项目 导入校验依赖 <dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>4.1.0.Final</version></dependency><dependency><groupId>javax.validation</…

Docker安装Redis,并在 Visual Studio Code 中使用它

Docker安装Redis 查找Redis docker search Redis完整结果 PS C:\Users\cheng> docker search Redis NAME DESCRIPTION STARS OFFICIAL redis Redis is an open …

System V IPC(进程间通信)机制详解

文章目录 一、引言二、System V IPC的基本概念1、IPC结构的引入2、IPC标识符&#xff08;IPC ID&#xff09;3、S ystem V的优缺点 三、共享内存&#xff08;Shared Memory&#xff09;1、共享内存的基本概念2、共享内存的创建&#xff08;shmget&#xff09;3、共享内存的附加…

python的文件操作及函数式编程介绍

五、文件操作 1、读取键盘输入 input 获取标准输入&#xff0c;数据类型统一为字符串 #!/usr/bin/python # -*- coding: UTF-8 -*- str input("请输入&#xff1a;") print&#xff08;"你输入的内容是: ", str&#xff09; 这会产生如下的对应着输入的…

KeyShot 2023.3 Pro for mac/win:完美融合3D渲染与动画制作

在当今数字化时代&#xff0c;视觉内容的创作和表现越来越受到重视。无论是产品设计、建筑规划&#xff0c;还是影视特效&#xff0c;都需要具备出色的3D渲染和动画制作工具来展现创意和想法。而作为业内领先的3D渲染和动画制作软件之一&#xff0c;KeyShot 2023.3 Pro在这个领…

电脑刚开机的时候不卡,用一会就变卡顿了…怎么回事?

前言 昨天咱们聊到旧电脑更换了固态硬盘之后&#xff0c;开机就会变快的事情&#xff0c;这个确实是可行且有效的升级电脑办法之一。 看完这篇之后&#xff0c;切莫着急升级电脑硬件配置&#xff0c;因为这里的坑比你想象的还要多。 从机械硬盘测试的数据和固态硬盘的测试数…

从CSDN搬家到微信公众号

博主将会在微信公众号里不断输出精品内容&#xff0c;陪伴大家共同成长。 如果你对博主的经历感兴趣&#xff0c;或者对博主的IT技术感兴趣&#xff0c;欢迎关注我的微信公众号&#xff0c;阅读我的技术文章&#xff0c;免费获取各种IT资源。也可以加我的微信成为我的好友&…

档案数字化加工是如何利用档案的

档案数字化加工是将纸质档案转化为数字形式&#xff0c;并进行后续的加工和利用。通过档案数字化加工&#xff0c;可以实现以下几个方面的利用&#xff1a; 1. 存储和保护&#xff1a;数字化档案可以将大量的纸质档案存储在数字存储介质中&#xff0c;从而节省空间和维护成本。…

面试算法之哈希专题

赎金信 class Solution { public:bool canConstruct(string ransomNote, string magazine) {// 小写字母int r_cnt[26];int m_cnt[26];for(int i 0; i< magazine.size(); i) {m_cnt[magazine[i]-a]; // 统计}// 对比for(int i 0; i< ransomNote.size(); i) {if(m_cnt[r…

使用vant-ui+vue3实现一个可复用的评星组件

如图所示 有两种情况 一种是5颗星 一种是3颗星 官网上只提供了图标类型的 并没有加文字 https://femessage-vant.netlify.app/#/zh-CN/ 自己结合两种情况 在全局注册了此组件(后续还会持续更新代码~) <template><div class"vant_rate_wrapper"><van…