javaScript箭头函数,作用域,闭包
函数作用域
函数作用域,在函数内部声明的变量只能在函数内部访问
函数内部声明的变量,函数外部无法被访问
函数的阐述也是函数内部的局部变量
不同的函数内部声明的变量无法相互访问
函数执行完毕后,函数内部的变量实际被清空了
块级作用域,let,const。var没有块级作用域
if (true){ let a = 10 console.log(a) //10 } console.log(a) //报错,从来未被定义 for (var i = 0; i < 10; i++) { console.log(i) //i = 10 } console.log(i) //i = 11
垃圾回收机制
js中内存的分配和回收都是自动完成的,内部再不使用的时候会被垃圾回收器自动回收
正式因为垃圾回收器的存在,许多人认为js不用太关心内存管理问题
如果不了解js的内存管理机制,我们很容易造成内存泄漏(内存无法被回收)的情况
不再使用的内存,没有及时被释放,就叫做内存泄漏
内存的生命周期
js环境中分配的内存,一般有如下生命周期
1,内存分配:当我们声明变量,函数,对象的时候,系统会自动为他们分配内存
2,内存使用:即读写内存,也就是使用变量,函数等
3,内存回收:使用完毕,由垃圾回收自动回收不再使用内存
注意点:全局变量一般不会回收(页面关闭的时候回收)一般情况下,局部变量的值,不再使用,会被自动回收掉
垃圾回收-引用计数法
1,跟踪记录每个值被引用的次数
2,如果这个值被引用一次,那么记录次数1
3,多次引用会累加
4,如果减少一个引用就减1
5,如果引用次数是0,则释放内存
注意点:当我们使用嵌套引用的时候,两个对象互相引用,那他们的引用次数永远都不可能是0,这样的互相引用如果说很大量的存在就会导致大量的内存泄漏
垃圾回收-清除标记法
总体思路一致,但是改进了一些算法
1,标记清除算法将不再使用的对象定义为无法达到的对象
2,就是从根部(在js中就是全局对象)出发定时扫页面内存中的对象。凡是能从根部到达的对象,都还是需要使用的。
3,那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收
闭包(Closure)
概念:一个函数对周围,状态的引用,捆绑在一起,内层函数中访问到其外层函数的作用域
w3c概念:能有权访问外层函数作用域中的变量就会生成闭包
简单理解:闭包 = 内层函数 + 外层函数的变量
闭包的作用:封闭数据,提供操作,外部也可以访问函数内部的变量,延长变量的使用时间;使我们的数据私有化,防止声明污染。
闭包的操作是基于作用域链
function fn() { let a = 10 function fun() { console.log(a) } // fun() return fun } // fn() // console.log(fn()) //返回整个函数体 const res = fn() res() //10返回函数结果 小括号为调用 // console.log(res()) //undefined // console.log(res) //返回函数体 // 写法3 fn()() //返回10 fn()是函数体,小括号是调用这个函数的返回值
私有化我们的数据
// 拓展 每次调用+1 // let i = 10 // function fun() { // console.log(i) // return function fn() { // i++ //调用一次加一次 // console.log(i) // } // return fn // } // fun() //函数体 // let res = fun() //函数体给他 // console.log(res) //调用的是fn函数体 // res() //小括号调用函数体里边的值,调用一次代码执行一次11 // res() //小括号调用函数体里边的值,调用一次代码执行一次12 // res() //小括号调用函数体里边的值,调用一次代码执行一次13 // 我们使数据私有化,别人动不得 function fn() { let i = 10 function f() { i++ console.log(i) } return f } fn()//这就是函数体 let res = fn() res() //调用函数表达式的结果,每次调用执行加1的操作 res() //调用函数表达式的结果,每次调用执行加1的操作 res() //调用函数表达式的结果,每次调用执行加1的操作
变量提升
变量提升是js中比较奇怪的现象,它允许在变量声明之前那就可以访问
只有var关键字声明的变量,会存在变量提升。变量在未声明即被访问的时候会出现语法错误。变量在声明致歉就被访问,变量没有被赋值,返回值为UNDEFINDED
let声明变量的时候不存在变量提升,推荐使用let。因为let有暂时性死区
console.log(age) // undefined var age = 10
动态参数(arguments)
我们函数的形参和实参本来应该是一一对应的,但是在极端情况下,会碰到实参不固定,我们也不使用数组的情况下,就需要动态参数
动态参数 arguments是函数内部内置的伪数组变量,它包含了调用函数时传入的所有实参
// 求多个数之间的累加和,随便的数 function fn() { console.log(arguments) //伪数组 索引便利 length属性 let sum = 0 for (let i = 0; i < arguments.length; i++) { console.log(arguments[i]) sum += arguments[i] } console.log(sum) } fn(1,3,4,5,6,7)
剩余参数(...参数名)
使用(...参数名),把剩余的参数都给到形参,也是使用数组的方式进行接收的
剩余参数我们获得的是真实数组
function fn(...res) { //接收剩余所有的实参 放到变量里面[] console.log(res) } fn(1,3,4,5,6,7,8,9)
展开运算符(...数组名)
将一个数组进行展开,不会改变原数组,运行场景:求数组中的最大,最小值,合并数组等操作
展开的数组会以字符串的形式呈现
const arr = [1,3,5,7,9] console.log(...arr) console.log(Math.min(...arr)) console.log(Math.max(...arr)) // 合并数组 const arr1 = [2,4,6] console.log(...arr,...arr1) console.log([...arr,...arr1]) let arr2 = [...arr,...arr1]
箭头函数
箭头函数是ES6新增的函数,目的就是为了简化函数写法,并且不绑定this,箭头函数的语法比函数表法式更简洁
箭头函数更适用那些本来需要匿名函数的地方,箭头函数中没有this指向,如果强制使用this指向,箭头函数的this指向当前所处作用域,箭头函数没有argument
const fn = function () { //函数表达式 console.log(`函数表达式`) } fn() const fun = () => { console.log(`函数表达式`) } fun() //如果形参只有一个 形参小括号可以省略 const fun1 = a => { console.log(`如果形参只有一个 形参小括号可以省略`)} fun1(1) //如果函数体只有一行代码,我们可以省略大括号 const fun2 = b => console.log(`如果函数体只有一行代码,我们可以省略大括号`) fun2(2) // 只有一行代码,return可以省略 const fun3 = (a,b) => a + b console.log(fun3(1,2)) // 箭头函数可以返回一个对象,用小括号包裹 const obj = name => ({uname:name}) // obj(`张学友`) console.log(obj(`张学友`))
数组的解构
解构赋值是一种快速为变量赋值的语法,本质上仍是为变量赋值,分为数组解构和对象解构两个大类型
数组解构是将数组的单元值快速批量赋值给一系列变量的简洁语法
赋值运算符:左侧的【】用来批量声明变量 = 右侧数组的单元值将被赋值给左侧的变量
变量的顺序对应数组单元值得位置,一一进行赋值操作
let arr = [1,3,5] let [a,b,c] = arr console.log(arr) console.log(a) console.log(b) console.log(c) let arr1 = `青苹果` let arr2 = `红苹果` ;[arr1, arr2] = [arr2, arr1] console.log(arr1,arr2)
数组解构的细节
<center> // let arr = [`王路飞`,`黑胡子`,`巴基`,`红发`] <br> // function fn() { <br> // return [1,2] <br> // } <br> // let [a,b] = fn() //fn() = [1,2] <br> // console.log(a,b) <br> // 当变量个数 比数组元素多 不匹配 <br> // let arr = [`王路飞`,`黑胡子`,`巴基`,`红发`] <br> // let [a,b,c,d,e,f] = arr <br> // console.log(a,b,c,d,e,f) //王路飞,黑胡子,巴基,红发,undefined,undefined <br> // 变量个数 比数组元素少 不匹配 <br> // let arr = [`王路飞`,`黑胡子`,`巴基`,`红发`] <br> // let [a,b,c] = arr <br> // console.log(a,b,c) //王路飞,黑胡子,巴基 <br> // 不需要数组中的某个元素 <br> // let arr = [`王路飞`,`黑胡子`,`巴基`,`红发`] <br> // let [a,b,,c] = arr <br> // console.log(a,b,c) //王路飞,黑胡子,红发 <br> // 后边两个数组房子数组当中 <br> // let arr = [`王路飞`,`黑胡子`,`巴基`,`红发`] <br> // let [a,b,...c] = arr <br> // console.log(a,b,c)//王路飞,黑胡子,[巴基,红发] <br> // 防止undefined <br> // let arr = [`王路飞`,`黑胡子`] <br> // let [a = 0,b = 0, c = 0] = arr <br> // console.log(a,b,c) //王路飞,黑胡子,0 <br> // 数组嵌套 <br> let arr = [1,3,5,[7,9]] <br> console.log(arr[0]) <br> console.log(arr[1]) <br> console.log(arr[2]) <br> console.log(arr[3]) //[7,9] <br> // let [a,b,c,[d,e]] = [1,3,5,[7,9]] <br> let [a,b,c,[d,e]] = arr <br> console.log(a) <br> console.log(b) <br> console.log(c) <br> console.log(d) <br> console.log(e) <br> </center> <script> // let arr = [`王路飞`,`黑胡子`,`巴基`,`红发`] // function fn() { // return [1,2] // } // let [a,b] = fn() //fn() = [1,2] // console.log(a,b) // 当变量个数 比数组元素多 不匹配 // let arr = [`王路飞`,`黑胡子`,`巴基`,`红发`] // let [a,b,c,d,e,f] = arr // console.log(a,b,c,d,e,f) //王路飞,黑胡子,巴基,红发,undefined,undefined // 变量个数 比数组元素少 不匹配 // let arr = [`王路飞`,`黑胡子`,`巴基`,`红发`] // let [a,b,c] = arr // console.log(a,b,c) //王路飞,黑胡子,巴基 // 不需要数组中的某个元素 // let arr = [`王路飞`,`黑胡子`,`巴基`,`红发`] // let [a,b,,c] = arr // console.log(a,b,c) //王路飞,黑胡子,红发 // 后边两个数组房子数组当中 // let arr = [`王路飞`,`黑胡子`,`巴基`,`红发`] // let [a,b,...c] = arr // console.log(a,b,c)//王路飞,黑胡子,[巴基,红发] // 防止undefined // let arr = [`王路飞`,`黑胡子`] // let [a = 0,b = 0, c = 0] = arr // console.log(a,b,c) //王路飞,黑胡子,0 // 数组嵌套 let arr = [1,3,5,[7,9]] console.log(arr[0]) console.log(arr[1]) console.log(arr[2]) console.log(arr[3]) //[7,9] // let [a,b,c,[d,e]] = [1,3,5,[7,9]] let [a,b,c,[d,e]] = arr console.log(a) console.log(b) console.log(c) console.log(d) console.log(e) </script>
对象解构
对象解构是将对象属性和方法快速批量赋值给一系列变量的简洁语法
赋值运算符:左侧的{ }用于批量生命变量 = 右侧对象的属性值。右侧的属性值将被赋值给左侧的变量
对象属性的值将被赋值给属性名相同的变量
const obj = { uname:`黄宁`, age:18, family:{ name:`小小宁`, agg: `3` } } // 对象解析 const {uname,age:b,family} = obj console.log(uname) let a = uname console.log(a) console.log(b) console.log(family) // const {uname,age,family:{name,agg}} = obj
多级对象解构(也就是对象中嵌套对象)
const obj = [ {uname : `黄宁`, family:{ son:`小黄`, sister:`3`}} ] // let {uname,family:{son,sister}} = obj let [{uname,family,family:{son,sister}}] = obj console.log(uname) console.log(family) //我么们保留对象 console.log(son) console.log(sister)
数组方法forEach
主要作用遍历数组,使用forEach只是用作循环处理,没有返回值所以不能使用return
let arr = [`王路飞`,`黑胡子`,`巴基`,`红发`] arr.forEach(function (item,index) { console.log(item) //数组返回值 console.log(index) //索引号 })
数组筛选filter(重点)
let arr = [`10`,`30`,`80`,`20`,`100`]
arr.filter( item => console.log(item >= 30))
综合使用方法
<!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>
// 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: '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',
},
]
// 渲染函数
function render(arr) {
let str = ''
arr.forEach((item) => {
// console.log(item) //每个对象
// console.log(index) //每个对象的索引
let {picture,name,price} = item //这里解析item,然后把所有的item中的数组,作为动态传值递给字符串拼接
// 使用字符串拼接的方法,把数组中所有的元素作为字符串拼接到一起
str += `<div class="item">
<img src="${picture}" alt="">
<p class="${name}"></p>
<p class="${price}"></p>
</div>`
// console.log(str)
})
document.querySelector(`.list`).innerHTML = str
}
render(goodsList)
// 事件源
// 找父级开启事件委托
const filter = document.querySelector(`.filter`)
// console.log(filter)
filter.addEventListener(`click`,function (e) {
// console.log(e)
const {target,target:{tagName,dataset}} = e
if (e.target.tagName === `A`){
// console.log(e.target.dataset.index)
// 默认就是全局
let arr = []
// 筛选0-100之间的价格
if(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 <= 200)
else if (dataset.index === `3`) arr = goodsList.filter((item) => item.price >= 300)
else arr = goodsList
// 每点击一次渲染一次页面
render(arr)
}
})
</script>
</body>
</html>

浙公网安备 33010602011771号