作用域
作用域对程序执行的影响及作用域链的查找机制,使得闭包函数创建隔离作用域避免全局变量污染。
作用域:规定了变量能够被访问的“范围”,离开了这个范围,变量便不能被访问。
作用域可以被分为:局部作用域、全局作用域
局部作用域
局部作用域分为:函数作用域和块作用域
函数作用域
在函数内部声明的变量,只能在函数内部被访问,外部无法直接访问。
function getSum(){
//函数内部是函数作用域、属于局部变量
const num = 10
}
console.log(num)//报错,超出作用域范围。
总结:
1.函数内部声明的变量,在函数外部无法被访问
2.函数的参数也是函数内部的局部变量
3.不同函数内部声明的变量无法互相访问
4.函数执行完毕后,函数内部的变量实际上被清空了
块作用域
在JavaScript中,使用{}包裹的代码称为“代码块”,代码块内部声明的变量,外部将【有可能(用var可以、var没有块级作用域)】无法被访问
for(let i = 1;i<=6;i++){
//i只能在该代码块中被访问
console.log(i)//正常
}
//超出i的作用域
console.log(i)//报错
如果使用var声明的变量,外部是可以被访问的
for(var i = 1;i<=6;i++){
console.log(i)//正常
}
console.log(i)//可以被访问
总结:
1.let声明的变量,会产生块级作用域。而var不会产生块级作用域
2.const声明的常量也会产生作用域
3.不同代码块之间的变量无法互相访问
4.推荐使用let或const
全局作用域
<script>标签和.js文件的【最外层】就是所谓的全局作用域,再次声明的变量在函数内部也可以被访问。
全局作用域中声明的变量,任何其他作用域都可以被访问。
<script>
//此处全局作用域
//全局作用域下声明了num变量
const num = 10
function fun(){
//函数内部可以使用全局作用域的变量
console.log(num)
}
//此处全局作用域
</script>
注意:
1.为window对象动态添加的属性,默认也是去全局的,不推荐!window.a = 10
2.函数中未使用任何关键字声明的变量为全局变量,不推荐!!!
3.尽可能少的声明全局变量,防止全局变量被污染。
作用域链
作用域链的本质:是底层的【变量查找机制】
1.在函数被执行时,会优先查找【当前函数作用域】中查找变量
2.如果【当前作用域】查找不到,则会依次逐层查找父级作用域,直到全局作用域。
<script>
//全局作用域
let a = 1
let b = 2
//局部作用域
function f(){
let a = 1
//局部作用域
function g(){
a = 2
console.log(a)
}
g()//调用g
}
f()//调用f
</script>
输出结果:2 2
总结:
1.嵌套关系的作用域,串联起来,形成了作用域链
2.相同作用域链中,按着从小到大的规则查找变量
3.子作用域能够访问父作用域,父作用域无法访问子级作用域。
JS垃圾回收机制
垃圾回收机制:(Garbage Collection)GC,JS中内存的分配和回收都是自动完成的,内存在不使用的时候就会被垃圾回收器自动回收。
正因为垃圾回收器的存在,许多人认为JS不用太关心内存管理的问题。
但如果不了解JS的内存管理机制,我们统一容易造成内存泄漏(内存无法被回收)的情况。
不再用到的内存,没有及时释放,就叫做内存泄漏。
内存的生命周期:
1.内存分配:当我们声明变量、函数、对象的时候,系统会自动为他们分配内存
2.内存使用:即读写内存,也就是使用变量、函数等
3.内存回收:使用完毕,由垃圾回收,自动回收不再使用的内存
4.全局变量一般不会被回收
5.一般情况下局部变量的值,不用了,会被自动回收掉
所谓垃圾回收,核心思想就是:如何判断内存是否已经不会再被使用了,如果是,就是为了垃圾,释放。
有常见的两种方法:引用计数法、标记清除法
引用计数法
引用计数法:就是看一个对象,是否有指向他的引用。
算法:
1.跟踪记录每个值被引用的次数
2.如果这个值,被用了一次,那么就记录次数1
3.多次引用就会累加
4.如果减少一个引用,就减1
5.如果引用次数是0,则释放内存
下方这个是一个块级作用域,按道理,块结束后,会将里面的内存释放掉。但是由于o1.a=o2、o2.a=o1他们相互指向,引用次数就会0+1=1,此时引用次数如果不是0,就不会被释放掉。因此在嵌套中,使用引用计数法,容易存在内存泄漏的问题。
标记清除法
标记清除法:现在的浏览器已经不再使用引用计数法了,而是基于标记清除法的算法,进行改进、但是总体思想都是一致的。
核心:
1.标记清除法:将“不再使用的对象”定义为“无法达到的对象”
2.就是从根部(JS全局对象)出发,定时扫描内存中的对象,凡是能从根部到达的对象,都是还需要使用的。
3.那些无法由根部触发触及到的对象、被标记为不再使用,稍后进行回收。
function fn(){
let o1 = {}
let o2 = {}
o1.a = o2
o2.a = o1
}
fn()
global从最外层往里面找,找到o1、o2,找到o1.a、找到o2.a,函数结束后,将o1、o2进行正常回收清除,但是o1.a和o2.a由于存在引用,没有被清除掉,但是在标记清除法中,global再次从外部来查找的时候,o1和o2已经被回收掉了,因此里面的o1.a和o2.a根本就找不到,因此给他进行标记,稍后进行回收。
闭包
闭包:一个函数对周围状态的引用,捆绑在一起。内层函数中访问到外层函数的作用域。
闭包 = 内层函数 + 外层函数的变量
function outer(){
let a = 1
function f(){
//里面的函数,使用外层函数的变量
console.log(a)
}
f()
}
outer()
闭包的作用:封闭数据,提供操作、外部也可以访问函数内部的变量。
基本格式:
function outer(){
let i = 1
function fn(){
console.log(i)
}
//将函数返回出去,不用写小括号,写小括号表示:调用
return fn
}
//outer() 返回者,等价于fn
const fun = outer()
fun() //1
//外层函数使用内部函数的变量
因为正常情况下,函数内部的值,我们是用不了的。
第二种常见的写法:既然我fn是一个函数,那我可以直接return:
function outer(){
let i = 1
return function(){
console.log(i)
}
}
const fun = outer()
fun()
第三种写法:
function outer(){
let i = 1
return function(){
return i
}
}
//outer() 接到了匿名函数
const fun = outer()
console.log(fun())
闭包的应用
闭包应用:实现数据的私有
比如,我们要做个统计函数调用次数,函数调用一次,就++
let i = 0
function fn(){
i++
console.log(i)
}
这样可以实现功能,但是我的i值很容易被篡改,这个时候通过闭包就可以实现数据的私有化。
function fn(){
let i = 0
return function(){
i++
console.log(i)
}
}
const test = fn()
console.log(test())
此时,外部想要在进行修改,就不会修改i的值,实现了数据的私有化。
那么此时i会被垃圾回收机制,回收掉吗?
答案是不会!因为const test = fn()是一个全局,全局作用域是不会被回收的、只有不使用的时候才会被回收。根据标记法,test会调用function,function又用到了fn中的i,一直再调用、一直被找到。所以不会被回收掉。
因此闭包会存在内存泄漏的风险。
变量提升
变量提升是JavaScript中比较“奇怪”的现象,它允许在变量声明之前就被访问(仅存在与var声明变量)
把所有var声明的变量,提升到 当前作用域的最前面
只提升声明,不提升赋值
console.log(num)//undefined
var num = 10
等价于=》
var num
console.log(num)//undefined
num = 10
注意:
1.变量在未声明,就被访问时,会报语法错误
2.变量在var声明之前被访问,变量的值是undefined
3.let/const声明的变量不存在变量提升
4.变量提升出现在相同作用域中
5.实际开发中,更推荐先声明,再访问变量
函数提升
会把所有函数声明,提升到当前作用域的前面
只提升函数声明,不提升函数调用
fn() //打印出来了
function fn(){
console.log('函数提升')
}
等价于:
function fn(){
console.log('函数提升')
}
fn()
function fn(){
console.log('函数提升')
}
函数表达式就不可以,比较特殊
fun()//undefined
var fun = function(){
console.log('函数表达式')
}
等价于=》
var fun
fun()//undefined
fun = function(){
console.log('函数表达式')
}
函数表达式:必须先赋值,后调用!!!他不存在函数提升现象!!!
函数参数
写一个求和函数:
不管用户传入几个实参,都要把和求出来!
这个时候就可以使用:动态参数
arguments是[函数内部内置的伪数组变量],它包含了调用函数时,传入的所有实参
function getSum(){
//arguments 动态参数,只存在于 函数中
console.log(arguments)//返回Arguments(2)伪数组,里面存放了2个参数值
}
getSum(2,3)
通过传入的参数,求参数和:
function getSum(){
let sum =
for(let i = 0;i<arguments.length;i++){
sum += arguments[i]
}
}
getSum(2,3,4)
getSum(2,3,4,5,6,7)
剩余参数
还是一个求和参数,但是不知道用于到底传进来多少实参,但是都要把它们的和求出来。
那我形参咋写?除了动态参数,还有剩余参数也可以实现。
剩余参数:允许我们将一个不定数量的参数表示为一个数组
function getSum(a,b...arr){
//使用的时候,不需要写... 直接拿就行
console.log(arr)//[3,4,5]
}
getSum(1,2,3,4,5)
a=1,b=2,剩下的3,4,5归于剩余参数
...是语法符号,置于最末函数的形参之前,用于获取多余的实参。
借助...获取的剩余实参,是一个真数组!这是比arguments优越的地方!
开发中,我们更提倡使用剩余参数
展开运算符
展开运算符(...),将一个数组进行展开
const arr = [1,5,3,8,2]
//展开一个数组
console.log(...arr) // 1,5,3,8,2
说明:
1.他不会修改原数组\
他最典型的应用场景:求数组最大值(最小值)、合并数组等
const arr = [1,2,3]
//Math.max中的参数,要求是字符串类型,因此数组被限制了
console.log(Math.max(1,2,3))
//求数组中的最大值,展开运算符返回的是字符串
console.log(Math.max(...arr))//3
console.log(Math.min(...arr))//1
合并数组:
const arr1 = [1,2,3]
const arr2 = [4,5,6]
const arr = [...arr1,...arr2]//1,2,3,4,5,6
剩余参数和展开运算符的区别:
剩余参数:【函数参数】中使用,得到真数组
展开运算符:【数组】中使用,数组展开
箭头函数
引入箭头函数,可以使用更简短的函数写法,并且不用绑定this,箭头函数语法比函数表达式更简洁
箭头函数更适用于那些本来需要匿名函数的地方
普通函数
const fn = function(){
console.log(123)
}
箭头函数
const fn = () => {
console.log(123)
}
fn()
const fn = (x) => {
console.log(x)//1
}
fn(1)
- 当箭头函数只有一个形参的时候,可以省略小括号
const fn = x => {
console.log(x)
}
fn(1)
- 当箭头函数只输出一句话的时候,可以省略大括号
const fn = x => console.log(x)
fn(1)
- 当箭头函数只输出一句话,并且是返回值,可以省略return
//return x+x的return被省略
const fn = x => x + x
fn(1)
-
更简洁的写法:
e是event,事件参数form.addEventListener('click',e => e.preventDefault()) -
箭头函数,可以直接返回一个对象
const fn = name => ({uname:name})
fn('刘德华')
name就是形参传过来的刘德华
因为对象是用{}来包裹的,而箭头函数中,输出语句也是用{}来包裹,为了造成问题,对象的输出需要用()来包裹
箭头函数参数
普通函数有arguments动态参数
箭头函数没有arguments动态参数,但是有剩余参数...args
利用箭头函数来求和
const getSum = (...args) => {
let sum = 0
for(let i =0;i<args.length;i++){
sum += args[i]
}
return sum
}
const result = getSum(2,3)
console.log(result)//5
箭头函数this
this指向:谁调用的这个,this就指向谁
console.log(this)//指向window
//普通函数
function fn(){
console.log(this)//指向window
}
因为函数:window.fn()
//对象方法中的this
const obj = {
name: 'andy',
sayHi:function(){
console.log(this)//这个方法是obj调用的
}
}
调用:obj.sayHi()
箭头函数出现之前,每一个新函数根据它是被如何调用的来定义这个函数的this值,非常令人讨厌。
但是!!!箭头函数不会创建自己的this,它只会从自己的作用域链的上一层沿用this
const fn = () => {
console.log(this)//window
}
这里不是因为默认window调用,箭头函数里没有this
这里是因为fn()是一个函数作用域,他的上一层是window,所以这里this指向的才是window
fn()
对象方法中的箭头函数this
const obj = {
uname:'pink',
sayHi:() => {
console.log(this)
}
}
obj.sayHi()//this指向window
sayHi()的作用域往上找,就是obj,而obj的this是由window调用的,所以这里返回window
cosnt obj = {
uname:'pink',
sayHi:function(){
let i = 10
const count = () => {
console.log(this)
}
count()
}
}
obj.sayHi()//obj;
箭头函数没有this,他的上一级就是他的this指向,
上一级是sayHi:function(),他的this指向是obj,因此返回obj
在开发中,【使用箭头函数前,需要考虑函数中this的值】,事件回调函数使用箭头函数时,this为全局的window,因此DOM事件回调函数为了简便,还是不太推荐使用箭头函数!
btn.addEventListener('click',function(){
console.log(this)//指向btn
})
btn.addEventListener('click',()=>{
console.log(this)//btn的this指向,就是window
})
数组解构
const arr = [100,60,80]
console.log(arr[0])
console.log(arr[1])
console.log(arr[2])
const arr = [100,60,80]
const max = arr[0]
const min = arr[1]
const avg = arr[2]
console.log(max)
console.log(min)
console.log(avg)
以前的写法太过于麻烦,我们通过数组解构来实现代码更简洁。
数组解构:将数组的单元值,快速批量的赋值给一系列变量的简洁语法。
const [max,min,avg] = [100,60,80]
console.log(max)
console.log(min)
console.log(avg)
基本语法:
1.赋值运算符 = 左侧的[]用于批量声明变量,右侧数组的单元值将被赋值给左侧的变量。
2.变量的顺序对应数组单元值的位置,依次进行赋值操作。
const arr = [100,60,80]
//数组解构 赋值
const [max,min,avg] = arr
数组解构的典型应用:交互2个变量;这里必须是let,因为const无法重新赋值。
let a = 1
let b = 3; //这里必须加分号
[b,a] = [a,b]
console.log(a)//3
console.log(b)//1
必须加分号的两种情况
1.立即执行函数:
(function(){})();
2.使用数组的时候:
const str = 'pink';
[1,2,3].map(function(item){
console.log(item)
})
因为不希望你用数组开头,进行书写。
let a = 1
let b = 2;
[b,a] = [a,b]
练习
const pc = ['海尔','联想','小米','方正']
const [hr,lx,mi,fz] = pc
function getValue(){
return [100,60]
}
const [max,min] = getValue()
数组解构特殊情况
-
变量多,单元值少的情况
const [a,b,c,d] = [1,2,3]
a=1、b=2、c=3、d:undefined -
变量少,单元值多的情况
const [a,b] = [1,2,3]
a=1,b=2 -
剩余参数 变量少,单元值多
const [a,b,...c] = [1,2,3,4]a=1,b=2,c=[3,4],c是以一个真数组的形式存储剩余参数 -
防止undefined传递、给个默认值就行
const [a='手机',b='华为'] = ['小米']a=小米,b=华为 -
按需导入,忽略某些返回值:
const [a,,c,d]=['小米','苹果','华为','格力']a=小米,c=华为,d=格力
多维数组解构
cosnt arr = [1,2 [3,4]]
console.log(arr[2])//[3,4]
console.log(arr[2][0])//3
用解构:
const arr = [1,2[3,4]]
const [a,b,c] = [1,2[3,4]]
console.log(a)//1
console.log(b)//2
console.log(c)//[3,4]
--------------------------------------
const [a,b[c,d]] = [1,2[3,4]]
console.log(a)//1
console.log(b)//2
console.log(c)//3
console.log(d)//4
对象解构
对象解构,是将对象属性和方法,快速批量的赋值给一系列变量的简洁语法。
基本语法:
1.赋值运算符=左侧的{}用于批量声明变量(const user),右侧对象的属性值将被赋值给左侧的变量
2.对象属性的值,将被赋值给属性名相同的变量
3.注意解构的变量名不要和外面的变量名冲突,否则报错
4.对象中找不到与变量名一致的属性时,变量值为undefined
//对象解构
const obj = {
uname : 'pink',
age : '18'
}
//obj.uname
//解构的语法
const {uname,age} = {
uname:'pink',
age:18
}
等价于:const uname = obj.uname
要求属性名和变量名必须一致。
对象解构变量重命名
const uname = 'red'
const {uname,age} = {uname:'pink',age:18}
我就是想外面也有一个叫uname的不行吗?
对象解构的变量名,可以重新改名:旧变量名:新变量名
const uname = 'red'
const {uname:username,age} = {uname:'pink',age:18}
冒号表示:x:y = x将值赋值给y
数组对象的结构
const pig = [
{
uname:'佩奇',
age:18
}
]
const [{uname,age}] = pig
多级对象解构
const pig = {
name:'佩奇',
family:{
mother:'猪妈妈',
father:'猪爸爸',
sister:'乔治'
},
age:6
}
//多级对象解构
const {name,family:{mother,father,sister},age} = pig
要加上对象的名字,进行多级对象的结构
数组对象解构:
const person = [
{
name:'佩奇',
family:{
mother:'猪妈妈',
father:'猪爸爸',
sister:'乔治'
},
age:6
}
]
const [{name,family:{mother,father,sister},age}] = person
多级案例
JSON对象格式:"msg":"信息",是双引号
// 1. 这是后台传递过来的数据
const msg = {
"code": 200,
"msg": "获取新闻列表成功",
"data": [
{
"id": 1,
"title": "5G商用自己,三大运用商收入下降",
"count": 58
},
{
"id": 2,
"title": "国际媒体头条速览",
"count": 56
},
{
"id": 3,
"title": "乌克兰和俄罗斯持续冲突",
"count": 1669
},
]
}
需求1: 请将以上msg对象 采用对象解构的方式
只选出 data 方面后面使用渲染页面
const {data} = msg
需求2: 上面msg是后台传递过来的数据,我们需要把data选出当做【参数】传递给 函数\
function render(arr){
const {data} = arr
//我们只要data数据,内部处理
console.log(data)
}
render(msg)
更简洁的写法:因为arr和data是一样的
function render({data}){
console.log(data)
}
render(msg)
需求3, 为了防止msg里面的data名字混淆,要求渲染函数里面的数据名改为 myData\
function render({data:myData}){
console.log(myData)
}
render(msg)
forEach遍历
forEach()方法用来调用数组的每个元素,并将元素传递给回调函数。
主要使用场景:遍历数组的每个元素;只遍历、不返回数组
语法:
被遍历的数组.forEach(function(当前数组元素,当前元素索引号)){
//函数体
}
const arr = ['red','green','pink']
arr.forEach(function(item,index){
console.log(item)//red green pink
console.log(index)//索引号
})
注意:
当前数组元素是必须要写的,索引号是选写
适合遍历【数组对象】
渲染商品案例
<div class="list">
<!-- <div class="item">
<img src="" alt="">
<p class="name"></p>
<p class="price"></p>
</div> -->
</div>
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',
},
]
0.声明一个字符串变量let str = ''
1.通过forEach遍历数据里面的数据
goodsList.forEach(item=>{
console.log(item)//可以得到每个数组元素,里面都是一个个对象
//循环数据,循环几次,就创建多少div
str += `
<div class="item">
<img src="" alt="">
<p class="name"></p>
<p class="price"></p>
</div>`
})
document.querySelector('.list').innerHTML = str
2.拿到数据,利用字符串拼接,生成解构,添加到页面中
goodsList.forEach(item=>{
//只要name,就解构name
const {name,price,picture} = item
str += `
<div class="item">
<img src="picture" alt="">
//解构前:<p class="name">${item.name}</p>
//解构后:<p class="name">${name}</p>
<p class="price">${price}</p>
</div>`
}
综合案例
tab栏切换:css写法
.filter a:active,
.filter a:focus {
background: #05943c;
color: #fff;
}
<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>
// 2. 初始化数据
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: '100.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',
},
]
//渲染
function render(arr){
//声明空字符串
let str = ``
//遍历数组 增加字符串
arr.forEach(item=>{
//解构
const {name,picture,price} = item
str += `
<div class="item">
<img src="${picture}" alt="">
<p class="name">${name}</p>
<p class="price">${price}</p>
</div>`
})
//追加给list
document.querySelector('.list').innerHTML = str
}
//页面一打开,就渲染数据
render(goodList)
filter筛选数组
filter()方法【创建一个新的数组】,新数组中的元素是通过检查指定数组中,符合条件的所有元素。
主要使用场景:筛选数组中符合条件的元素,并返回筛选之后元素的新数组。
语法:
const arr = [10,20,30]
//会返回一个新数组,需要接收一下
const newArr = arr.filter(item=>{
//找出大于等于20的数组
return item >= 20
})
简写(省略了return和大括号):const newArr = arr.filter(item=> item>=20)
filter()中item必须写,index是可以选的,因为返回的是一个新数组,所以对原数组没有影响。
//过滤筛选
document.querySelector('.filter').addEventListener('click',e=>{
//e.target 这个里面有tagName和dataset的属性,解构出来
const {tagName,dataset} = e.target
//判断 (e.target.tagName === 'A')
if(tagName === 'A'){
//arr是返回的新数组,先将goodList赋值给arr,因为如果点4就是渲染全部,需要将goodList拿过来
let arr = goodList
if(dataset.index === '1'){
arr = goodList.filter(item=>
item.price > 0 && item.price <= 100)
}
else if(dataset.index === '2'){
arr = goodList.filter(item=>
item.price >= 100 && item.price <= 300)
}
//如果点的是4,4标签是渲染全部
render(arr)
}
})