• JS中call(),apply()是什么,call(),apply()的原理是什么?如何手写一个call(),apply()?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 小时 之间 哦 !!!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    🎐 apply()

    apply()和call()的差别只是传递的第一个参数之后的参数的形式不同,call()是分开写,apply是数组

    func.call(person,1,2,3)  
    func.apply(person,[1,2,3])
    
    • 1
    • 2

    所以在这里详细讲解一下call()方法的实现
    apply()的实现只是在call()接受参数的时候使用剩余参数
    apply()使用一个数组,别的都一样

    手写代码见本文末尾

    🎡手写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: "猪脚饭"}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    再来看一下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
    
    • 1
    • 2
    • 3
    • 4
    • 5

    🎶第二步:设置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: ƒ}
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

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

    使用…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 8
          return numA + numB
        }
        const res = func.myCall(person, 2, 8)
        console.log('返回值为:', res) // 返回值为: 10
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    🎉 测试
        Function.prototype.myCall = function (thisArg, ...args) {
          thisArg.f = this
          const 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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    ✨第四步:使用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");
    // 这三个都不相等
    
    • 1
    • 2
    • 3
    • 4
       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 //把原函数的返回值返回出去
        }
        
        
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    🎉测试
       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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

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

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

    ✨手写apply() :myApply()

       Function.prototype.myApply = function (thisArg, args) {//相较于myCall() 只是 ...args=>args
          const key = Symbol('key')
          thisArg[key] = this
          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.myApply(student, [1, 2, 3])
        console.log('返回值:', res2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    🎉测试

    在这里插入图片描述

  • 相关阅读:
    wireshark——解密加密报文
    宜居行星最新报道
    【安卓APP毕业设计源码】基于Android的健康食谱交流app
    BertTokenizer 使用方法
    【Eclipse】安装教程
    服从正态分布的正弦函数、余弦函数期望
    9-5 Prometheus的blackbox_exporter实现对URL状态, ICMP可用性, Port状态, TLS证书监控
    Addflow for WPF 2019 Crack
    【Js】数据处理
    Hive表【汇总】
  • 原文地址:https://blog.csdn.net/sinat_51673411/article/details/132746945