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.hqwc.cn/news/101683.html

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

相关文章

r 安装源码包 安装本地r包

总结一下手动安装R包 - 简书 (jianshu.com)https://www.jianshu.com/p/2a7a36414734 #BiocManager::install("simplifyEnrichment") #BiocManager::install("EnsDb.Hsapiens.v86")#下载包 之后 手动安装 #install.packages("~/datasets/EnsDb.Hsapien…

Android Studio中创建java项目

1.创建普通的android工程 2.创建一个module 3.module类型选择java library 4.填写libary和class的名字 5.生成的工程如图所示 6.然后点击Run --- Edit Configurations... 选择Application选项 设置所需要的参数 选中myjavalib后点击OK。然后打开刚创建的lib的gradle 编辑gradl…

【LeetCode-中等题】208. 实现 Trie (前缀树)

文章目录 题目方法一:利用数组构建26叉树方法二:利用哈希表构建26叉树 题目 方法一:利用数组构建26叉树 插入图示: 全搜索和前缀搜索: 注意:全局匹配匹配完直接返回插入时的标志位 而前缀匹配时&#xff…

Web存储

目录 什么是 HTML5 Web 存储? 方法 cookie webStorage 会话存储 sessionStorage 本地存储localStorage 什么是 HTML5 Web 存储? 使用HTML5可以在本地存储用户的浏览数据。 早些时候,本地存储使用的是 cookie。但是Web 存储需要更加的安全与快速. 这些数据不会被保存在服…

element-ui dialog弹窗 设置点击空白处不关闭

根据官网提供方法 场景:vue实现的网站有两个弹窗同时出现时,关闭报警,批量进度条弹窗也关闭了, 1、每一个页面都有可能出现的报警弹窗, 2、页面a批量操控硬件添加操作的进度条弹窗 开始以为是因为点击报警弹窗&#…

命令行git联网失败,但是实际可以联网

最近下载代码的时候发现总是告诉我连不上github的网页,但是我自己通过浏览器又可以上网,找了半天发现这个方法可以。 记录下这个代理 打开git bash 执行以下命令: git config --global http.proxy http://127.0.0.1:7890 git config --glob…

力扣(LeetCode)算法_C++——有效的数独

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图) …

关于Comparable、Comparator接口返回值决定顺序的问题

Comparable和Comparator接口都是实现集合中元素的比较、排序的,下面先简单介绍下他们的用法。 1. 使用示例 public class Person {private String name;private Integer age;public Person() {}public Person(String name, Integer age) {this.name name;this.ag…

在学习DNS的过程中给我的启发

在国内,关于DNS相关的话题一直络绎不绝,比如DNS根服务器为什么中国没有,还有Anycast BGP实现负载,为什么DNS只有13个,还有DNS over HTTPS 和 DNS over TLS的优劣等等问题,接下来我会找出几个一一说一下其中…

stable diffusion实践操作-常见lora模型介绍

系列文章目录 本文专门开一节写Lora相关的内容,在看之前,可以同步关注: stable diffusion实践操作 文章目录 系列文章目录前言一、什么是lora?1.1 lora 定义1.2 lora的基本原理1.2 通过分层控制lora 二、作用:2.1 复刻人物特征2…

教育培训小程序的设计与功能解析

随着互联网的发展,线上教育逐渐成为一种趋势,越来越多的人开始选择在线学习。而搭建一个适合自己的线上教育小程序,可以为教育机构或个人提供更好的教学和学习体验。在本文中,我们将介绍如何通过一个第三方制作平台来搭建在线教育…