JS中call方法是什么,call()的原理是什么?如何手写一个call()?Symbol是什么,怎么用Symbol调优?含详细解析

🎉call()

💕call()的参数

thisArg:在调用 func 时要使用的 this 值
arg1, …, argN (可选) 函数的参数

✨call()的描述:

首先声明 func是一个函数,person是一个对象
针对这段代码:func.call(person,‘a1’,‘a2’)
调用func方法并传递两个参数’a1’,‘a2’ ,以及把func中的this设置为person对象

🍧call()的代码解释

 function greet (a,b) {console.log(this)console.log(this.animal, "的睡眠时间一般在", this.sleepDuration, "之间",a, b)}const obj = {animal: "猫",sleepDuration: "12 到 16 小时",}greet.call(obj, "哦", "!!!") // {animal: '猫', sleepDuration: '12 到 16 小时'}//猫 的睡眠时间一般在 12 到 16 小时 之间 哦 !!!

🎡手写Call() :myCall()

❤️步骤

手写Call() 分为四步

  1. 定义myCall方法,加在Function原型上,使得所有函数都能点出来使用
  2. 设置this并调用原函数
  3. 接收剩余参数并返回结果
  4. 使用Symbol调优

🎶前置知识 this指向问题

  1. 全局执行环境中,指向全局对象window(非严格模式、严格模式)

  2. 函数内部,取决于函数被调用的方式
    2.1. 直接调用的this值:

    • 非严格模式:全局对象(window)
    • 严格模式:undefined

    2.2 对象方法调用的this值:

    • 调用者
  3. 开启严格模式

    • 脚本开启: ‘use strict’
    • 函数内部开启:‘use strict’
    • 注意:'use strict’写在代码顶端
 // ------------- 1.全局执行环境 -------------//  严格模式,非严格模式 全局对象(window)// 'use strict'// console.log(this)// ------------- 2.函数内部 -------------// 2.1 直接调用-非严格模式// function func() {//   console.log(this) // window// }// func()// 2.1 直接调用-严格模式// function func() {//   'use strict'//   console.log(this) // undefined// }// func()// 2.2 对象方法调用const food = {name: '猪脚饭',eat() {'use strict'console.log(this)}}// 非严格模式,严格模式food.eat() // 调用者 Object {eat: ƒ eat(),name: "猪脚饭"}

再来看一下MDN的解释 MDN地址

✨下面这点很重要

o.f() 就使得 函数 f 中的 this 指向 对象 o

在这里插入图片描述
先定义一个对象o,在定义一个函数independent(),然后把函数追加到对象o中和上述可以实现一样的效果
在这里插入图片描述

🎀第一步:定义myCall方法,加在Function原型上,使得所有函数都能点出来使用

在Function对象的原形上通过"."的方式添加myCall属性,并给这个对象赋值一个函数

  Function.prototype.myCall = function () {console.log("this is myCall")}function greet () { }greet.myCall()// this is myCall

🎶第二步:设置this并调用原函数

🎐图解

在这里插入图片描述
由于给person多加了一个f属性,所以后面需要使用 delete关键词 把f属性删掉

🎏代码

     Function.prototype.myCall = function (thisArg) {thisArg.f = this //这个this就是原函数func(因为 根据前置知识的讲解 func.mycall()使得函数myCall的this指向func )// ,这段代码是在person(thisArg在这里就是person)对象上面增加一个属性,属性名为f 属性值为func(){...}thisArg.f()//根据前置知识 f的this是thisArg,在这里f是func 这样就完成了第二步}// ------------- 测试代码 -------------const person = {name: 'zhangsan'}function func (numA, numB) {console.log(this)console.log(numA, numB)return numA + numB}const res = func.myCall(person) // {name: 'zhangsan', f: ƒ}

🎄第三步:接收剩余参数并返回结果

使用…args接收剩余参数,并用解构赋值的方法把参数传递给调用者

Function.prototype.myCall = function (thisArg, ...args) {thisArg.f = this  const res = thisArg.f(...args) //args=>[2,8] ...args=>2,8 把剩余参数传给func (numA=2,numB=8)delete thisArg.f //删除person中新加的f属性return res}// ------------- 测试代码 -------------const person = {name: 'zhangsan'}function func(numA, numB) {console.log(this) //Object{name:zhangsan}console.log(numA, numB) //2 8return numA + numB}const res = func.myCall(person, 2, 8)console.log('返回值为:', res) // 返回值为: 10

在这里插入图片描述

🍿 测试

    Function.prototype.myCall = function (thisArg, ...args) {thisArg.f = thisconst res = thisArg.f(...args) delete thisArg.f return res}// ------------- 测试代码 -------------const student = {name: 'lisi'}function func2 (a, b, c) {console.log(this)console.log(a, b, c)return a + b + c}const res2 = func2.myCall(student, 1, 2, 3)console.log('返回值:', res2)

在这里插入图片描述

✨第四步:使用Symbol调优

🎶关于Symbol

Symbol的MDN链接

symbol 是一种基本数据类型(primitive data type)。
Symbol() 函数会返回 symbol类型的值,该类型具有静态属性和静态方法。

每个从 Symbol() 返回的 symbol 值都是唯一的。一个 symbol 值能作为对象属性的标识符;

🍧symbol的使用

直接使用Symbol()创建新的 symbol 类型,并用一个可选的字符串作为其描述。这个描述只是为了看着方便没有实际用处。(MDN解释:对 symbol 的描述,可用于调试但不是访问 symbol 本身。)

var sym1 = Symbol();
var sym2 = Symbol("foo");
var sym3 = Symbol("foo");
// 这三个都不相等
   Function.prototype.myCall = function (thisArg, ...args) {const key = Symbol('key')// 使用Symbol创建一个唯一的symbol值 作为对象的标识符// thisArg.key 是给thisArg对象增加一个名为字符串'key'的属性thisArg[key] = this //thisArg[key] 是把key作为一个变量 实际传过去的是Symbol('key')const res = thisArg[key](...args)delete thisArg[key]return res}

🎉测试

   Function.prototype.myCall = function (thisArg, ...args) {const key = Symbol('key')// 使用Symbol创建一个唯一的symbol值 作为对象的标识符// thisArg.key 是给thisArg对象增加一个名为字符串'key'的属性thisArg[key] = this //thisArg[key] 是把key作为一个变量 实际传过去的是Symbol('key')const res = thisArg[key](...args)delete thisArg[key]return res}// ------------- 测试代码 -------------const student = {name: 'lisi'}function func2 (a, b, c) {console.log(this)console.log(a, b, c)return a + b + c}const res2 = func2.myCall(student, 1, 2, 3)console.log('返回值:', res2)

这个是谷歌浏览器的结果,谷歌这点有点显示bug
在这里插入图片描述

Edge就没有,下图是Edge浏览器的结果
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Json“牵手”亚马逊商品详情数据方法,亚马逊商品详情API接口,亚马逊API申请指南

亚马逊平台是美国最大的一家网络电子商务公司,亚马逊公司是1995年成立,刚开始只做网上书籍售卖业务,后来扩展到了其他产品。现在已经是全世界商品品种最多的网上零售商和第二互联网公司,亚马逊是北美洲、欧洲等地区的主流购物平台…

【2023最新版】腾讯云CODING平台使用教程(Pycharm/命令:本地项目推送到CODING)

目录 一、CODING简介 网址 二、CODING使用 1. 创建项目 2. 创建代码仓库 三、PyCharm:本地项目推送到CODING 1. 管理远程 2. 提交 3. 推送 4. 结果 四、使用命令推送 1. 打开终端 2. 初始化 Git 仓库 3. 添加远程仓库 4. 添加文件到暂存区 5. 提交更…

OPENCV+QT环境配置

【qtopencv开发入门:4步搞定opencv环境配置2】https://www.bilibili.com/video/BV1f34y1v7t8?vd_source0aeb782d0b9c2e6b0e0cdea3e2121eba 第一步: 安装QT Qt 5.15 第二步: 安装OPENCV VS2022 Opencv4.5.5 C 配置_愿飞翔的鱼儿的博客…

认识doubbo和rpc

开个新坑,和大家一起学习Dubbo 3.X。我们按照一个由浅入深顺序来学习,先从使用Dubbo开始,再深入Dubbo的核心原理。 今天我们就从认识Dubbo开始,整体的内容可以分为3个部分: Dubbo是什么RPC是什么Dubbo的架构 正式开…

uniapp项目实践总结(十一)自定义网络检测组件

导语:很多时候手机设备会突然没网,这时候就需要一个网络检测组件,在没网的时候显示提示用户,提供用户体验。 目录 准备工作原理分析组件实现实战演练案例展示 准备工作 在components新建一个q-online文件夹,并新建一个q-online.vue的组件;…

[刷题记录]牛客面试笔刷TOP101

牛客笔试算法必刷TOP101系列,每日更新中~ 1.合并有序链表2023.9.3 合并两个排序的链表_牛客题霸_牛客网 (nowcoder.com) 题意大致为: 将两个链表中的元素按照从小到大的顺序合并成为一个链表. 所给予的条件: 给出的所要合并的链表都是从小到大顺序排列的. 思路: 创建一…

[Java]异常

目录 1.异常的概念与体系结构 1.1异常的概念 1.1.1算术异常 1.1.2数组越界异常 1.1.3空指针异常 1.2异常的体系结构 1.3异常的分类 2.异常的处理 2.1 防御式编程 2.2异常的抛出 2.3异常的捕获 2.3.1 异常声明throws 将光标放在抛出异常方法上,alt Insert …

SAC算法

SAC算法 全称Soft Actor-Critic算法,为优化目标引入了熵约束项,增大了动作的探索性,避免陷入局部最优解,原论文 继承了Soft Q-Learning提出了Soft Policy Iteration,进而推导了Soft Actor-Critic参数更新时机&#xff…

RCU501 RMP201-8 KONGSBERG 分布式处理单元

RCU501 RMP201-8 KONGSBERG 分布式处理单元 AutoChief600使用直接安装在主机接线盒中的分布式处理单元。进出发动机的所有信号都在双冗余CAN线路(发动机总线)上传输。 所有不重要的传感器都可以与K-Chief 600报警和监控系统共享,只需要一个主机接口。这一原则大大…

Redis之SDS底层原理解读

目录 SDS是什么? SDS结构示例 概述 空间预分配 惰性空间释放 C字符串跟SDS的区别?为什么用SDS? SDS是什么? Redis 底层的程序语言是由 C 语言编写的,C 语言默认字符串则是以空字符结尾的字符数组&#xff08…

【C++】异常

目录 一、概念二、异常的使用1、异常的抛出和捕获2、异常的重新抛出3、异常安全4、异常规范 三、自定义异常体系四、C标准库的异常体系五、异常的优缺点 一、概念 传统的错误处理机制: 终止程序,如assert,缺陷:用户难以接受。如…

Apache Tomcat漏洞复现

文章目录 弱口令启动环境漏洞复现 本地文件包含启动环境漏洞复现 弱口令 启动环境 来到vulhub/tomcat/tomcat8/靶场 cd vulhub/tomcat/tomcat8/安装环境并启动: sudo docker-compose up -d && sudo docker-compose up -d修改端口后启动: su…

十七、MySQL约束演示

1、约束定义 (1)概念 约束,顾名思义,时作用域表中字段上的规则,用于限制存储在表中的数据,主要用于保证数据库中数据的正确、有效性和完整性。 (2)各种约束分类 1、非空约束(限制…

企业网络小实验-MUX-Vlan(NAT)

路漫漫其修远兮,吾将上下而求索 直接上实验 实验说明 模拟公司的部门实验, (1)公司主机如图所示,配置DNS服务器,配置NAT地址转换(使用easy-ip的形式)访问外网。 (2&…

go语言的高级特性

go语言调用C语言 go tool cgo main.go

【JAVA】面向对象的编程语言(继承篇)

个人主页:【😊个人主页】 系列专栏:【❤️初识JAVA】 文章目录 前言继承类的继承方式继承的各种类型多继承继承的特性各种继承关键字extends关键字implements关键字super 与 this 关键字super 关键字this 关键字 final 关键字 前言 在之前的…

Java中网络的基本介绍。网络通信,网络,ip地址,域名,端口,网络通信协议,TCP/IP传输过程,网络通信协议模型,TCP协议,UDP协议

- 网络通信 概念:网络通信是指通过计算机网络进行信息传输的过程,包括数据传输、语音通话、视频会议等。在网络通信中,数据被分成一系列的数据包,并通过网络传输到目的地。在数据传输过程中,需要确保数据的完整性、准…

【EI/SCOPUS会议征稿】第二届环境遥感与地理信息技术国际学术会议(ERSGIT 2023)

第二届环境遥感与地理信息技术国际学术会议 2023 2nd International Conference on Environmental Remote Sensing and Geographic Information Technology 第二届环境遥感与地理信息技术国际学术会议(ERSGIT 2023)定于2023年11月10-12日在中国陕西西安…

“搞事情”?OpenAl将于11月召开其首届开发者大会

摘要:OpenAI也要召开它的第一届开发者大会了。这次活动,或许标志着OpenAI向其下一阶段的商业开发迈出了关键一步。 昨天,OpenAI宣布将于11月6日举办其首次开发者大会。在这场名为“OpenAI DevDay”的活动中,OpenAI的技术人员将进行…

10、哈希函数与哈希表

哈希函数 出现次数最多的 32G 小文件方法:利用哈希函数在种类上均分 设计RandomPool结构 设计一种结构,在该结构中有如下三个功能: insert(key):将某个key加入到该结构,做到不重复加入 delete(key):将原本在结构中的某个key移除 getRando…