JS笔试手撕题

news2024/11/17 5:45:56

数据劫持

Vue2的Object.defineProperty()

Vue2的响应式是通过Object.defineProperty()拦截数据,将数据转换成getter/setter的形式,在访问数据的时候调用getter函数,在修改数据的时候调用setter函数。然后利用发布-订阅模式,在数据变动时触发依赖,也即发布更新给订阅者,订阅者收到消息后进行相应的处理

描述符分为数据描述符和存取描述符,只能是其中之一,不可两者同时存在
在这里插入图片描述
configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为false。
enumerable:表示能否通过for in循环访问属性,默认值为false
//数据描述符
1.writable:表示能否修改属性的值。默认值为false。
2.value:包含这个属性的数据值。默认值为undefined。
//存取描述符
1.get:在读取属性时调用的函数,默认值是undefined
2.set:在写入属性的时候调用的函数,默认值是undefined

  <script>
        function defineReactive(data) {
            if (!data || Object.prototype.toString.call(data) !== '[object Object]')
                return
            for (let key in data) {
                let val = data[key]
                Object.defineProperty(data, key, {
                    configurable: true,//可配置
                    enumerable: true,//可枚举
                    set: function (newval) {
                        console.log('调用set');
                        if (newval === val) {
                           return ;
                        }
                        console.log('属性值发生变化');
                        val = newval

                    },
                    get() {
                        console.log('调用get');
                        return val
                    },

                })
                if (typeof val === 'object') {
                    defineReactive(val)
                }
            }
        }
        const data = {
            name: 'better',
            firends: ['1', '2']
        }
        defineReactive(data)

        console.log('data.friends[0]:', data.firends[0]);
        console.log('data.name:', data.name);
        data.name = 'lihua'
        console.log('更改后的data.name:', data.name);
        data.friends[0] = '100'
        // 在JavaScript中,数组是一种特殊的对象,因此直接对数组进行defineProperty并不能监听数组元素的变化。
        // 当我们尝试修改数组元素时,比如data.friends[0] = 100,实际上并不会触发set函数,也就无法实现数组元素的响应式更新。
        console.log('更改后的data.friends[0]:', data.firends[0]);

    </script>

在这里插入图片描述
弊端:
1.无法劫持对象的添加和删除操作,Vue2的解决方法(新增set和delete)
2.无法劫持到数组的api(push、pop…),Vue2的解决方法是重写数组的api
3.存在深层嵌套关系,通过无脑递归,但也会劫持到项目始终都不会用到的对象,造成性能损耗

Vue3的proxy(解决vue2响应式的弊端)

Proxy(代理):用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
Reflect(反射):对源对象的属性进行操作

Vue3基于ES6新增的Proxy对象实现数据代理以及通过Reflect对源数据进行操作,它解决了Vue2中无法追踪数据新增或删除属性的问题。另外,Proxy可以直接监听数组,无需像Vue2响应式那样需要重写数组方法进行拦截

proxy详解

const p = new Proxy(target, handler)
//target:要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
//handler:一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
 <script>

        function isObject(obj) {
            if (typeof obj !== "object" || !obj) {
                return false;
            }
            return true;
        }

        // vue3使用reactive定义响应式对象时返回的就是reactive的实例
        function reactive(obj) {
            // 对整个对象进行劫持
            return new Proxy(obj, {
                get(target, key) {
                    console.log('get:', key);
                    // proxy想要监听深层对象也需要进行递归处理,不过这里用懒加载,用不到的属性不用进行深层监听
                    let res = Reflect.get(target, key)
                    return isObject(res) ? reactive(res) : res;
                },
                set(target, key, value) {
                    console.log('set:', key, value);
                    return Reflect.set(target, key, value)
                },
                deleteProperty(target, key) {
                    console.log('delete', key);
                    return Reflect.deleteProperty(target, key)
                }
            })
        }

        let person = reactive({ name: 'zs', age: 18, job: { code: "前端" } })
        console.log('person.name:', person.name);
        // 直接对proxy实例操作
        person.name = '小张'
        console.log('------------');
        person.gender = '男'
        delete person.age
        console.log('------------');
        console.log('测试对数组的监听');
        //数组的push方法,作为push的属性理应也该被劫持到
        let arr = reactive([1, 2, 3, 4, 5])
        arr.push(11)

        console.log('--------------------');
        console.log('对深层对象的测试');
        console.log('person.job.code:', person.job.code);
        person.job.code = "php"


    </script>

在这里插入图片描述

总结
优点

1.Proxy直接劫持整个对象,并返回一个新对象,我们可以只操作新的对象达到响应式的目的
2.Proxy可以直接监听数组的变化(push,shift,splice…)
3.Proxy有多达13中拦截方法,不限于apply、ownKeys、deleteProperty、has等等,这是Object.defineProperty所不具备的
4.Proxy懒加载,解决递归造成的性能问题

缺点

Proxy不兼容IE

闭包

 <script>
        function fn1() {
            debugger;
            let num = 999;
            function innerFn1() {
                debugger;
                console.log(num);
            }
            innerFn1()
        }
        fn1()
    </script>

在这里插入图片描述
函数依赖外部变量就形成闭包
在这里插入图片描述

闭包的应用场景

函数内部return出去一个函数,就是结合了闭包的应用场景之一,目的是为了让那个闭包持久化

    <script>
        function fn1() {
            debugger;
            let num = 999;
            function innerFn1() {
                debugger;
                console.log(num);
            }
           return innerFn1
        }
        let closure1=fn1();//闭包 num:999
        // 两个不同的闭包,因此闭包可以解决全局变量命名冲突问题
        let closure2=fn1();//闭包 num:999
    </script>
<script>
        // 面试题
        function fn3(a, b) {
            console.log('第二个参数的值是:', b);
            return {
                innerFn: function (c) {
                    return fn3(c, a);
                }
            }
        }
        // 链式调用
        fn3(1).innerFn(2).innerFn(3).innerFn(4)
        // 1.外部调用 传递a:1 返回一个对象 形成闭包 (a:1)=>输出undefined
        // 2.传递c:2 执行函数,并返回一个对象  fn3(c,a) (c:2,a:1)=>输出1
        // 3.外部a:2,b:1,返回一个对象(a:2)
        // 4.参数c:3,执行fn(3,2)   外部:(a:3,b:2)=>输出2
        // 5.闭包(a:3)
    </script>

在这里插入图片描述

        // 面试题
        function fn(a, b) {
            debugger
            console.log('第二个参数的值是:', b);
            return {
                //对象中的函数形成一个闭包
                fn: function (c) {
                    debugger
                    return fn(c, a)
                }
            }
        }
        let obj = fn(1)
        // 一个新对象有一个闭包=>1个
        // 访问的都是同一个闭包
        obj.fn(2)
        obj.fn(3)
        obj.fn(4)

在这里插入图片描述

 <script>
        // 面试题
        function fn(a, b) {
            debugger
            console.log('第二个参数的值是:', b);
            return {
                //对象中的函数形成一个闭包
                fn: function (c) {
                    debugger
                    return fn(c, a)
                }
            }
        }
        // let obj = fn(1)
        // // 一个新对象有一个闭包=>1个
        // // 访问的都是同一个闭包
        // obj.fn(2)
        // obj.fn(3)
        // obj.fn(4)

        console.log('----------------');
        let a = fn(1).fn(2)
        a.fn(3).fn(4)
        a.fn(5).fn(6)

    </script>

在这里插入图片描述

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

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

相关文章

计算机专业,求你别再玩了,我都替你们着急

明确学习目标和方向&#xff1a;确定自己希望在计算机领域的哪个方向深入发展&#xff0c;如前端开发、后端开发、数据库管理、人工智能等。根据目标方向&#xff0c;制定详细的学习计划&#xff0c;确保所学知识与未来职业方向相匹配。 【PDF学习资料文末获取】 扎实基础知识…

effective python学习笔记_推导与生成

用推导取代map和filter 序列推导可取代map和filter&#xff0c;优越性有&#xff1a;1可读性强2不需要map的函数 控制推导逻辑的子表达式不要超过2个 即推导的for层数最多建议两层&#xff0c;多了可读性会下降&#xff0c;反而用for循环会清晰 一层for内可连接多个if&…

为什么要使用大模型

随着OpenAI引领的超大模型风潮&#xff0c;大模型的发展日新月异&#xff0c;如同雨后春笋般茁壮成长。在现今的科技舞台上&#xff0c;每周&#xff0c;甚至每一天&#xff0c;我们都能见证到一个全新模型的开源&#xff0c;这些模型的创新性和实用性不断超越前作&#xff0c;…

激光雷达技术:科技之眼,照亮前行

在科技与人文关怀的交响乐章中&#xff0c;一项名为“蝙蝠避障”使用了激光雷达技术原理及应用的创新成果&#xff0c;正悄然改变着视障朋友们的生活方式&#xff0c;为他们的日常出行铺设了一条充满希望的光明之路。今天&#xff0c;让我们一起深入探讨这项技术如何成为盲人出…

关于Java Chassis 3的契约优先(API First)开发

契约优先&#xff08;API First&#xff09;开发是指应用程序开发过程中&#xff0c;将API设计作为第一优先级的任务。契约优先开发随着Web Services概念的发展而不断得到重视&#xff0c;特别是微服务架构出现以后&#xff0c;API设计成为影响功能开放、性能优化等问题的关键因…

企业外贸邮箱有哪些?国内五大外贸邮箱排行榜

外贸公司在进行跨国业务的时候&#xff0c;需要一个稳定安全的企业邮箱。国内的企业外贸邮箱提供商有很多&#xff0c;目前排行在前五的有Zoho Mail企业邮箱、阿里企业邮箱、网易企业邮箱、腾讯企业邮箱、新浪企业邮箱&#xff0c;今天我们就来详细了解下这些邮箱产品。 一、Z…

球形帐篷:低碳环保的未来多功能建筑—轻空间

球形帐篷是一种创新的建筑形式&#xff0c;以其环保、可持续的特点&#xff0c;正在逐渐成为未来多功能建筑的新趋势。通过采用气膜技术和轻量化材料&#xff0c;球形帐篷将为观众带来与众不同的观影、展览等体验&#xff0c;同时彰显了科技创新与环保共生的理念。 创新科技与环…

VTK数据的读写--Vtk学习记录1--《VTK图形图像开发进阶》

读和写操作是VTK可视化管线两端相关的类--Reader和Writer类 Reader:将外部数据读入可视化管线&#xff0c;主要步骤如下 s1:实例化Reader对象 s2:指定所要读取的文件名 s3:调用Update()促使管线执行 对应的Writer: s1:实例化Writer对象 s2输入要写的数据以及指定写入的文…

N个行业看板组态数据可视化大屏,海量模板库不用代码拖拉就行

芯软云设备管理大数据平台。 芯软云设备管理大数据平台&#xff0c;提供MES工艺模板、能源管理模板、智慧水务模板、智慧农业模板、实际产量、设备管理模板、布局模板等。用户可以选择自己喜欢并适合的模板进行场景构建。平台还提供除模板外&#xff0c;共五大类场景资源&…

IP地址证书的详细申请步骤

IP地址证书申请的条件有两个&#xff0c;一个是此IP必须是公网IP&#xff0c;另一个是IP的80和443端口必须允许短暂开放。满足这两个条件才能为其部署SSL证书。 IP地址ssl证书申请网址链接https://www.joyssl.com/certificate/select/ip_certificate.html?nid16 1 访问提供IP…

【PyTorch实战演练】使用CelebA数据集训练DCGAN(深度卷积生成对抗网络)并生成人脸(附完整代码)

文章目录 0. 前言1. CelebA数据集1.1 核心特性与规模1.2 应用与用途1.3 获取方式1.4 数据预处理 2. DCGAN的模型构建2.1 生成器模型2.2 判别器模型 3. DCGAN的模型训练&#xff08;重点&#xff09;3.1 训练参数3.2 模型参数初始化3.3 训练过程 4. 结果展示4.1 loss值变化过程4…

前端基础知识-ES6解构赋值(将数组内元素、字符串内字符、对象内属性值快速赋值给其他变量)

前言&#xff1a; 将数组、字符串、对象进行展开&#xff0c;并将展开的数据赋值给指定变量&#xff0c;以达到语法简化的目的&#xff0c;日常开发中可以大大提升我们的效率。 主要语法&#xff1a; 一、[变量1,变量2。。。]目标数组 将数组里面的内容赋给其他变量 场景1…

Linux流程控制

if语句 基本格式 if condition thencommand1 fi 写成一行 if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi if-else语句 格式 if condition thencommand1 command2...commandN elsecommand fi if else- if else if condition1 th…

3月空气净化器市场数据分析,热门品牌排行榜揭晓!

三月上旬以来&#xff0c;中国空气净化器行业的规模持续扩大&#xff0c;市场规模和消费需求也在不断提升&#xff0c;消费者对高质量空气的需求增加。智能化是当前空气净化器市场的一个重要发展方向&#xff0c;这类产品集成了空气过滤、监测等功能&#xff0c;满足了现代消费…

信创 | 信创基础设施建设:国内外对比分析研究

信创基础设施建设在国内外的比较分析涉及到多个方面&#xff0c;包括政策支持、产业发展现状、技术进步、市场应用等。通过综合分析&#xff0c;我们可以得出以下结论&#xff1a; 政策支持与发展方向&#xff1a;中国自2019年以来&#xff0c;陆续出台了一系列政策支持信创产业…

[C++基础编程]----预处理指令简介、typedef关键字和#define预处理指令之间的区别

目录 引言 正文 01-预处理指令简介 02-typedef关键字简介 03-#define预处理指令简介 04-#define预处理指令和typedef关键字的区别 &#xff08;1&#xff09;原理不同 &#xff08;2&#xff09;功能不同 &#xf…

贪心+线段树,CF720A. Closing ceremony

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 Problem - 720A - Codeforces 二、解题报告 1、思路分析 如果人都在左上角…

顶级SCI优化!24年新算法冠豪猪算法CPO优化无人机集群三维路径规划!先用先发!

声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 结果展示 原理讲解 一、路径长度成本 F1 …

斯坦福大学的在线密码学课程

密码学是保护计算机系统信息不可或缺的工具。在本课程中&#xff0c;您将了解密码系统的内部工作原理&#xff0c;以及如何在实际应用中正确使用它们。课程首先将详细讨论当强大的对手窃听和篡改流量时&#xff0c;拥有共享密钥的双方如何进行安全通信。我们将研究许多已部署的…

EtherCAT运动控制器Delta机械手应用

ZMC406硬件介绍 ZMC406是正运动推出的一款多轴高性能EtherCAT总线运动控制器&#xff0c;具有EtherCAT、EtherNET、RS232、CAN和U盘等通讯接口&#xff0c;ZMC系列运动控制器可应用于各种需要脱机或联机运行的场合。 ZMC406支持6轴运动控制&#xff0c;最多可扩展至32轴&#…