day-031-thirty-one-20230320-瀑布流-节流-作用域
瀑布流
-
与后端数据交互
- 客户端通过ajax发送到服务器得到json字符串数据
- 通过JSON.parse()把得到的json字符串数据转成json对象
-
循环渲染DOM元素 - 得到json对象数据后,循环插入html中
- 根据观察,发现数据,不适合直接渲染;
- 使用map循环修改源数据得到自己想要的数据
- 对数据进行分组,根据图片大小依次反向插入对应列中
- 数据循环遍历,步长为瀑布流总列数
- 每次拿到一个数组长度为步长的图片数据数组,按照图片高度从大到小排列。同时对每一列的总高度用offsetHeight比较,从小到大排序,得到一个瀑布流DOM列数组。
- 对图片数据数组进行遍历,将数据插入到对应角标的瀑布流DOM列中。
- 数据循环遍历,步长为瀑布流总列数
- 根据观察,发现数据,不适合直接渲染;
-
实现瀑布流效果
- 创建监控器对象
- 监控器对象第一个入参回调函数里代码思路
- 循环判断所有内容入参的状况
- 若当前内容的isIntersecting为true,则对图片进行懒加载
- 对图片进行懒加载的过程中,记得给已经懒加载赋一个表示已经加载完成的自定义属性,用于取消对当前图片的父元素–图片盒子的监控。
- 若当前内容的isIntersecting为true,则对图片进行懒加载
- 循环判断所有内容入参的状况
- 第二个入参为{ threshold:[1] }表示被监控元素全部出现或消失一个边才触发第一个回调函数
- 监控器对象第一个入参回调函数里代码思路
- 循环监控所有图片盒子
- 优化思路为 图片盒子是依赖于未懒加载图片的父元素进行查找的。
- 如document.querySelectorAll(‘.img-box img[data-src]’)或document.querySelectorAll(‘.img-box img[src=“”]’),之后循环找这些元素的父元素
- 优化思路为 图片盒子是依赖于未懒加载图片的父元素进行查找的。
- 创建监控器对象
-
实现加载更多的效果
- 在瀑布流容器的下方创建一个DOM元素,定义一个计数变量
- 创建监控器对象来监听瀑布流容器的下方创建一个DOM元素
- 第一个入参为一个回调函数,回调函数第一个形参为changes
- 若changes[0].isIntersecting,则执行第1、第2、第3步,并让计数变量自增加1。如果计数变量到指定数值,则取消对瀑布流容器的下方DOM元素的监控。
- 第二个入参为{ threshold:[0.5] }表示被监控元素出现一半或消失一半才触发第一个回调函数
- 第一个入参为一个回调函数,回调函数第一个形参为changes
节流
- 节流概念
- 每隔一定时间,只执行第一次触发的事件
- 节流场景
- 全局滚动
- 多次点击
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body style="height: 3000px;">
<h1>1111</h1>
</body>
<script>
const throttle = function throttle(func, wait) {
if (typeof func !== "function")
throw new TypeError("func must be an function");
if (typeof wait !== "number") wait = 300;
let timer,
previous = 0;
return function proxy(...params) {
let now = +new Date(),
remaining = wait - (now - previous),
self = this,
result;
if (remaining <= 0) {
if (timer) {
clearTimeout(timer);
timer = null;
}
result = func.call(self, ...params);
previous = now;
} else if (!timer) {
timer = setTimeout(() => {
if (timer) {
clearTimeout(timer);
timer = null;
}
result = func.call(self, ...params);
previous = +new Date();
}, remaining);
}
return result;
};
};
function show() {
console.log("111");
}
window.onscroll = throttle(show, 500);
</script>
</html>
作用域
-
变量 函数—作用域 (域: 某个区域)
- 变量和函数才有作用域的概念
-
作用域(两大类)
- 全局作用域: 在任何地方都可以使用
- 全局作用域里面的变量叫做全局变量,VO
- 全局作用域里面的函数叫做全局函数
- 全局作用域里面执行代码,会创建一个全局执行上下文
- 全局作用域里面的变量叫做全局变量,VO
- 私有作用域: 在某个私有区域里面使用,超出无法使用
- 具有
- 函数私有作用域
- 块级私有作用域
- 私有作用域里面的变量或者形参叫做私有变量,AO
- 私有作用域里面的函数叫做私有函数
- 私有作用域里面执行代码,会创建一个私有执行上下文
- 函数私有上下文
- 块级私有上下文
- 具有
- 块级作用域 也属于私有使用域,ES6新增
var a=10; function fn(){ // b属于私有作用域 // f1属于私有作用域 console.log(a); var b=20; console.log(b); function f1(){ console.log(b); } f1() } fn(); console.log(a); console.log(b);
var a=3; function fn(){ var b=6; console.log(a);//3 } fn(); console.log(b);//b is not defined
- 全局作用域: 在任何地方都可以使用
能运行js代码的地方
- 浏览器
- nodejs
- nodejs要想运行js代码
- 安装node.js
- 使用命令提示窗口
-node xxx.js
- nodejs要想运行js代码
- webview
- 一般就是手机默认内嵌的html浏览视口
//nodejs 要想运行js代码
//1. 安装nodesjs
//2. 使用"命令提示窗口" node XXX.js
console.log("111");
- ECStack(Execution context Stack) 执行环境栈(栈内存,从内存中分配出来的一块内存)
- EC(Execution Context)执行上下文(在编程语言中,代码执行,为了区分全局作用域和函数执行所处不同的作用域,目的是为了区分每个词法作用域下代码的独立性)EC 就是代码执行所处的范围
- EC(g):全局执行上下文
- EC(function):函数执行的上下文
- VO 和AO:在每一个执行上下文中,代码执行的时候,都会存贮一些变量:
- 全局上下文中的变量存储在VO
- 私有上下文中的变量存储在AO
- GO:浏览器把一些内置的属性和方法放到了GO中,并且在全局执行上下文(EC (g))中创建了一个window变量对象,并且让其指向GO
作用域链
-
在私有作用域中,在查找变量的时候,先看自己私有作用域中有没有同名变量
- 如果有,就用自己的同名变量
- 如果没有,就会向上一级作用域进行查找
-
上级作用域有,就用上级作用域的同名变量
-
如果也没有,一直向上查找,直到找到全局作用域为止
- 如果全局作用域有,就使用全局作用域的同名变量
- 如果全局作用域也没有,就去window上找同名属性
- 如果window上也没有,分两种情况:
- 如果只是查找,就会报错
- 如果是赋值,就相当于给全局作用域添加属性和属性值
- 即给window添加了该属性,即给全局作用域添加了一个全局变量
- 相当于在全局用var声明了该同名变量
- function也把函数放在window上
- 如果window上也没有,分两种情况:
// var a=10; // function fn(x,y){ // //私有作用域: // // AO:b,x,y // var b=100; // } // fn(30,40) function fn(){ console.log(n);//n is not defined } fn(); //var n // function fn(){ // n=3; // } // fn(); // console.log(n);//3 // function fn(){ // n=3;//把全局n=2 改为 n=3 // } // var n=2; // fn(); // console.log(n);//3 // function fn(){ // console.log(n);//2 // } // var n=2; // fn(); // console.log(n);//2
var x=12; let y=13; z=14; console.log(window.x); console.log(window.y); console.log(window.z); console.log(x); console.log(y); console.log(z);
-
-
全局执行上下文 EC(G)
-
私有执行上下文
- 函数私有执行上下文EC(function)
- 块级私有执行上下文EC(block)
-
块级作用域 {},除了对象以外
-
条件1 要是用ES6语法
-
let
-
const
-
const 声明变量
- 常量不可改变
- 基础数据类型值不能更改
- 引用数据类型内的属性可以更改,但引用地址依旧不能更改
- 声明常量的时候,必须赋初始值
// const a=10; // a=100;//Assignment to constant variable //console.log(a); // const a; // a=100;//Assignment to constant variable // const arr=[1,2,3];//arr---0x001 // arr.push(40);//允许 // console.log(arr);//arr---0x001 // arr=[];//不允许
- 常量不可改变
-
-
class
-
-
条件2 要用花括号包起来
{ let a=10; } console.log(a);//a is not defined
-
内存概念升级
- 浏览器一打开,就会创建一个栈内存和堆内存
- 栈内存里
- 浏览器会在堆内存中,会开辟一个空间,来存放一系统属性和方法,叫
全局对象Global Object
,简称GO
变量提升
- 变量提升
- var 会变量提升
- 声明变量会提升到当前私有作用域最头上,但赋值操作还在原来的地方
- let 没有变量提升,在let声明之前使用变量,会报错
- function 会变量提升 声明和赋值都会提升到当前块级作用域最头上
- ES5既声明又赋值
- ES6只声明不赋值,声明操作会提升到当前私有作用域最头上,但赋值操作还在原来的地方,类似于var
- var 会变量提升
- 变量提升的特殊性
-
if判断的结果值,结果值不论是true或false,不会影响变量提升
-
if判断中,不看判断条件结果为true或false,function都会变量提升,只提升不赋值,跟var一样
- 但执行if语句时,以function作为分界线,
- function语句到块级作用域上方,应用ES5规则
- 既声明又赋值,并且该变量是全局变量
- 既对这个变量的操作在此时还是操作全局变量的
- function语句到块级作用域下方,应用ES6规则
-
只声明不赋值,到执行时才声明,并且该变量是块级变量
(() => { console.log(a, "|--1--|");//undefined "|--1--|" if (true) { console.log(a, "|--2--|");//ƒ a() {} "|--2--|" a = 6; console.log(a, "|--3--|");//6 "|--3--|" function a() {} //---------------------此时a就为局部作用域 console.log(a, "|--4--|");//6 "|--4--|" a = 3; console.log(a, "|--5--|");//3 "|--5--|" } console.log(a, "|--6--|");//6 "|--6--|" })(); // 相当于 (() => { var a; console.log(a, "|--1--|");//undefined "|--1--|" if (true) { a = function a() {}; console.log(a, "|--2--|");//ƒ a() {} "|--2--|" a = 6; console.log(a, "|--3--|");//6 "|--3--|" //---------------------旧函数所在位置,此时a就为局部作用域 if (true) { console.log(a, "|--4--|");//6 "|--4--|" //私有作用域里面没有a,所以沿着作用域链往上找a为6 } if (true) { let a = 3; //变量a在函数声明后的第一次赋值就是第一次的局部作用域声明 console.log(a, "|--5--|");//3 "|--5--|" } } console.log(a, "|--6--|");//6 "|--6--|" })();
-
- function语句到块级作用域上方,应用ES5规则
- 但执行if语句时,以function作为分界线,
-
没有var或function,变量不会做提升
-
自执行函数本身不会做变量提升
- 但自执行函数里面的内容依旧可以做变量提升
//变量提升 // var 会变量提升 声明变量会提升到最头上,赋值还在原来的地方 // let 没有变量提升 // function 会变量提升 声明和赋值都会提升到最前面 // console.log(a);//undefined // var a=10; // console.log(a);//10 // var a; // console.log(a);//undefined // a=10; // console.log(a);//10 // console.log(a);//报错 // let a=10; // console.log(a); // console.log(fn);//函数 // function fn(){ // console.log("111"); // } // console.log(fn);//函数 // function fn(){ // console.log("111"); // } // console.log(fn);//函数 // console.log(fn);//函数 // var a=2; // var b=a; // b=3; // console.log(b)//3 // console.log(fn(1,2)); //3 // function fn(n,m){ // return n+m; // } // console.log(fn(1,2));//3
// 变量提升的特殊性: // 1. if 判断的结果值(true,false),不会影响变量提升,var 会变量提升 // 2. 新: // if 判断中,不看判断条件,function 会变量提升,只提升不赋值(跟var一样) // console.log(a);//undefined // if(1=="1"){ // console.log(a);//undefined // var a=2; // console.log(a);//2 // } // console.log(a);//2 // console.log(a);//undefined // if(1=="2"){ // console.log(a); // var a=2; // console.log(a); // } // console.log(a);//undefined // console.log(a);//undefined // if("a" in window){//true // var a=100; // } // console.log(a);//100 // console.log(fn); // if(1=="2"){ // console.log(fn); // function fn(){}; // console.log(fn); // } // console.log(fn); // console.log(fn);//undefined // if(1=="1"){//当条件满足时,function 会再次变量提升+赋值 // console.log(fn); //fn // function fn(){}; // console.log(fn);//fn // } // console.log(fn);//fn // console.log(fn);//undefined // if(1=="1"){ // console.log(fn); //fn // function fn(){};//以函数体为分界线,上面为全局作用域,下面为块级作用域 // fn=3 // console.log(fn);//3 // } // console.log(fn);//fn //不会做变量提升 // console.log(a);//报错 // a=10 // console.log(a); // console.log(a);//报错 // a=function(){} // console.log(a); //自执行函数本身不会做变量提升,里面的内容依旧可以做变量提升 //(function(){})() // // 全局作用域: // // 全局变量VO(G)/GO: // // f,g // f=function(){ // return true; // }; // g=function(){ // return false; // }; // ~function(){ // // 私有执行上下文: // // 私有变量AO(AN): // // g---undefined // if(g()&&[]==![]){//undfiend() // f=function(){return false}; // function g(){ // return true; // } // } // }(); // console.log(f()); // console.log(g()); // // 全局作用域: // // 全局变量VO(G)/GO: // // f---true--false,g---false // f=function(){ // return true; // }; // g=function(){ // return false; // }; // ~function(){ // // 私有执行上下文: // // 私有变量AO(AN): // // g---undefined---- return true; // if([]==![]){//满足条件,再次变量提升+赋值 // f=function(){return false}; // function g(){ // return true; // } // } // }(); // console.log(f()); // console.log(g()); //console.log([]==![]) //true // console.log(![])//false //console.log([]==false)//true //[]--->0 false---》0
// console.log(fn);//undefined // if(1==1){//true 重新变量提升+赋值 // console.log(fn);//函数 // function fn(){ // console.log("ok"); // } // } // console.log(fn)//函数 // 变量提升 a---函数--1 //var a=0; // if(true){//再次 提升+赋值 // a=1;//(全局) // function a(){} // a=21; // console.log(a);//21(块级私有) // } // console.log(a);//1 //变量提升 num--und--100 fn---und---函数 // console.log(num);//undefined // console.log(fn);//undefined // if([]){//再次 提升+赋值 // // 只要进到当前if条件中,会立即对fn进行赋值; // fn()//a // var num=100; // function fn(){console.log("a")} // } // console.log(fn);//函数 // console.log(num);//100
//变量提升 a--und--函数--6 // console.log(a, '1');//undefined 1 // if (true) {// 变量提升+赋值 // console.log(a, '2');//函数,2 // a = 6; // console.log(a, '3');//6,3 // function a() {}//以它为分界线后面都是私有(块) // console.log(a, '4');// 私有里面有a吗? 没有 沿着作用域链,往上找 6, 4 // a = 3; //私有的块级作用域,里面有 a---3 // console.log(a, '5');//3,5 // } // console.log(a, '6');// 6,6
-