前端学习点 无论什么时候都不要把自己当一回事,要把自己做的事情当一回事。要经得住诱惑,耐得住寂寞。

浏览器渲染机制、重绘、重排

网页生成过程:

HTML 被 HTML 解析器解析成 DOM 树
css 则被 css 解析器解析成 CSSOM 树
结合 DOM 树和 CSSOM 树,生成一棵渲染树(Render Tree)生成布(flow),即将所有渲染树的所有节点进行平面合成将布局绘制(paint)在屏幕上重排(也称回流): 当 DOM 的变化影响了元素的几何信息(DOM 对象的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,
这个过程叫做重排。

触发:

  1. 添加或者删除可见的 DOM 元素
  2. 元素尺寸改变——边距、填充、边框、宽度和高度
    重绘: 当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来
    的过程,叫做重绘。 触发:改变元素的 color、background、box-shadow 等属性

重排优化建议:

  1. 分离读写操作
  2. 样式集中修改
  3. 缓存需要修改的 DOM 元素
  4. 尽量只修改 position:absolute 或 fixed 元素,对其他元素影响不大
  5. 动画开始 GPU 加速,translate 使用 3D 变化
    transform 不重绘,不回流 是因为 transform 属于合成属性,对合成属性进行
    transition/animate 动画时,将会创建一个合成层。这使得动画元素在一个独
    立的层中进行渲染。当元素的内容没有发生改变,就没有必要进行重绘。浏览器会通过重新复合来创建动画帧

闭包

闭包是指有权访问另一个函数作用域中的变量的函数 ——《JavaScript 高级程
序设计》
当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行 ——《你不知道的 JavaScript》
闭包用途:

  1. 能够访问函数定义时所在的词法作用域(阻止其被回收)
  2. 私有化变量
  3. 模拟块级作用域
  4. 创建模块
    闭包缺点:会导致函数的变量一直保存在内存中,过多的闭包可能会导致
    内存泄漏
/* 
        1.闭包closure是什么 : 
            a. 闭包 是一个 访问其他函数内部变量 的 函数
            b. 闭包 = 函数 + 上下文引用

        2.闭包作用 : 解决变量污染
            * 一般用于回调函数

        3.在浏览器中调试闭包 :
        */    

        document.querySelector('.btn').onclick = function(){
    
    

            //1.获取用户搜索的内容
            let txt = document.querySelector('input').value
            //2.网络请求 : 不是立即就能出结果的,网络请求需要时间的。
            //使用定时器来模拟请求
            setTimeout(function(){
    
    
                alert(`${
    
    txt}的搜索结果如下:123条`)
            },1000)
        }

递归

  /* 
        1.递归函数:  一个函数 在内部 调用自己
            * 递归作用和循环类似的,也需要有结束条件

        2.递归应用:
        
        */    

        function fn(){
    
    
            console.log('今天学得很开心')
            fn()
        }

        // fn()

        //双函数递归 : 两个函数互相调用
        function fn1(){
    
    
            console.log('哈哈')
            fn2()
        }

        function fn2(){
    
    
            console.log('呵呵')
            fn1()
        }

        // fn1()

深拷贝, 浅拷贝

 /* 
        1.递归函数:  一个函数 在内部 调用自己
            * 递归作用和循环类似的,也需要有结束条件

        2.递归应用:
            浅拷贝与深拷贝 : 
                方式一(推荐) : JSON方式实现
                    * let newObj = JSON.parse( JSON.stringify( obj ) )
                方式二(递归) : 了解
            遍历dom树
        */  
       
        let obj = {
    
    
            name:'张若曦',
            age:16,
            sex:'男',
            hobby:['吃饭','睡觉','学习']
        }

        //浅拷贝: 拷贝地址
        // let newObj = obj
        // 修改拷贝后的数据,原数据也会修改
        // newObj.name = '张若曦'
        // console.log( obj,newObj)

        //深拷贝 : 拷贝数据
        //(1)先把js对象 -> JSON字符串   (JSON会自动帮你深拷贝)
        // let jsonStr = JSON.stringify( obj )
        //(2)再把 JSON字符串 -> js对象
        // let newObj = JSON.parse( jsonStr )

        let newObj = JSON.parse( JSON.stringify( obj ) )

        newObj.name = '张若曦'
        console.log(obj,newObj)

原型、原型链

原型: 对象中固有的__proto__属性,该属性指向对象的 prototype 原型属性。
原型链: 当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。原型链的尽头一般来说都是Object.prototype 所以这就是我们新建的对象为什么能够使用 toString()等方法的原因。
特点: JavaScript 对象是通过引用来传递的,我们创建的每个新对象实体中并
没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。

事件冒泡、捕获(委托)

事件冒泡指在在一个对象上触发某类事件,如果此对象绑定了事件,就会
触发事件,如果没有,就会向这个对象的父级对象传播,最终父级对象触
发了事件。
事件委托本质上是利用了浏览器事件冒泡的机制。因为事件在冒泡过程中
会上传到父节点,并且父节点可以通过事件对象获取到目标节点,因此可
以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多
个子元素的事件,这种方式称为事件代理。
event.stopPropagation() 或者 ie 下的方法 event.cancelBubble = true; //
阻止事件冒泡

Http 和 Https 区别

1.HTTP 的 URL 以 http:// 开头,而 HTTPS 的 URL 以 https:// 开头
2.HTTP 是不安全的,而 HTTPS 是安全的
3.HTTP 标准端口是 80 ,而 HTTPS 的标准端口是 443
4.在 OSI 网络模型中,HTTP 工作于应用层,而 HTTPS 的安全传输机制工作在传输层
5.HTTP 无法加密,而 HTTPS 对传输的数据进行加密
6.HTTP无需证书,而 HTTPS 需要 CA 机构 wosign 的颁发的 SSL 证书

GET 和 POST 区别

1.GET 在浏览器回退不会再次请求,POST 会再次提交请求
2.GET 请求会被浏览器主动缓存,POST 不会,要手动设置
3.GET 请求参数会被完整保留在浏览器历史记录里,POST 中的参数不会
4.GET 请求在 URL 中传送的参数是有长度限制的,而 POST 没有限制
5.GET 参数通过 URL 传递,POST 放在 Request body 中
6.GET 参数暴露在地址栏不安全,POST 放在报文内部更安全
7.GET 一般用于查询信息,POST 一般用于提交某种信息进行某些修改操作
8.GET 产生一个 TCP 数据包;POST 产生两个 TCP 数据包

前端性能优化的几种方式

  1. 浏览器缓存
  2. 防抖、节流
  3. 资源懒加载、预加载
    4.开启 Nginx gzip 压缩
    三个方面来说明前端性能优化
    一: webapck 优化与开启 gzip 压缩
    1.babel-loader 用 include 或 exclude 来帮我们避免不必要的转译,不
    转译 node_moudules 中的 js 文件
    其次在缓存当前转译的 js 文件,设置 loader:
    ‘babel-loader?cacheDirectory=true’
    2.文件采用按需加载等等
    3.具体的做法非常简单,只需要你在你的 request headers 中加上这么一
    句:accept-encoding:gzip
    4.图片优化,采用 svg 图片或者字体图标
    5.浏览器缓存机制,它又分为强缓存和协商缓存
    二:本地存储——从 Cookie 到 Web Storage、IndexedDB
    说明一下 SessionStorage 和 localStorage 还有 cookie 的区别和优缺点
    三:代码优化
    1.事件代理
    2.事件的节流和防抖
    3.页面的回流和重绘
    4.EventLoop 事件循环机制
    5.代码优化等等

防抖节流

函数防抖关注一定时间连续触发,只在最后执行一次,而函数节流侧重于一段时间内只执行一次。
防抖


//定义:触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
//搜索框输入,避免不停发送Ajax(造成后端)只需用户最后一次输入完,再发送请求
//手机号、邮箱验证输入检测 onchange oninput 事件
//窗口大小 Resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。
const debounce = (fn, wait, immediate) => {
    
    
let timer = null;
return function (...args) {
    
    
if (timer) clearTimeout(timer);
if (immediate && !timer) {
    
    
fn.call(this, args);
}
timer = setTimeout(() => {
    
    
fn.call(this, args);
}, wait);
};
};
const betterFn = debounce(() => console.log("fn 防抖执行了"), 3000,
true);
document.addEventListener("scroll", betterFn);

节流

扫描二维码关注公众号,回复: 14270231 查看本文章
//应用场景:游戏技能点击后需要一定时间才能使用(使用间隔时间内触发不会成功)
//定义:当持续触发事件时,保证隔间时间触发一次事件。
//1. 懒加载、滚动加载、加载更多或监听滚动条位置;
//2. 百度搜索框,搜索联想功能;
//3. 防止高频点击提交,防止表单重复提交;
function throttle(fn,add){
    
    
let pre = 0;
return function(...args){
    
    
let now = Date.now();
if( now - pre >= add){
    
    
fn.apply(this,args);
pre = now;
}
}
}
function handle(){
    
    
console.log(Math.random());
}
window.addEventListener("mousemove",throttle(handle,3000));

数组去重,数组对象去重 filter indexOf […new Set(arr)]

//数组
const arr = [2,7,5,7,2,8,9];
console.log([...new Set(arr)]); // [2,7,5,8,9];
//对象
const list = [{
    
    age:18,name:'张三'},{
    
    age:18,name:'李四'},{
    
    age:18,name:' 王五'}]
let hash = {
    
    };
const newArr = arr.reduce((item, next) => {
    
    
hash[next.age] ? '' : hash[next.age] = true && item.push(next);
return item;
}, []);
console.log(list);

方法

var arr = [1,2,3,4,2,3,4,2,1,5];
var newArr = []; //定义一个新的空数组

for (var i = 0; i < arr.length; i++) {
    
    
    if (newArr.indexOf(arr[i]) === -1) {
    
    
    	//如果在新数组中找不到该项值,则推入新数组中
        newArr.push(arr[i]);
    }
}

console.log(newArr);   // [1, 2, 3, 4, 5]

```c
var arr = [1,2,3,4,2,3,4,2,1,5];
var newArr = arr.filter((item, index, arr) => arr.indexOf(item) === index);

console.log(newArr)  // [1, 2, 3, 4, 5]
//indexOf:从头部开始搜索,返回第一次找到的索引

猜你喜欢

转载自blog.csdn.net/qq_43944285/article/details/124504971