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

JS中call方法是什么,call()的原理是什么?如何手写一个call()?Symbol是什么,怎么用Symbol调优?含详细解析_第1张图片
先定义一个对象o,在定义一个函数independent(),然后把函数追加到对象o中和上述可以实现一样的效果
JS中call方法是什么,call()的原理是什么?如何手写一个call()?Symbol是什么,怎么用Symbol调优?含详细解析_第2张图片

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

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

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

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

图解

JS中call方法是什么,call()的原理是什么?如何手写一个call()?Symbol是什么,怎么用Symbol调优?含详细解析_第3张图片
由于给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 8
      return numA + numB
    }
    const res = func.myCall(person, 2, 8)
    console.log('返回值为:', res) // 返回值为: 10


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

测试

    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)

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

✨第四步:使用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
JS中call方法是什么,call()的原理是什么?如何手写一个call()?Symbol是什么,怎么用Symbol调优?含详细解析_第6张图片

Edge就没有,下图是Edge浏览器的结果
JS中call方法是什么,call()的原理是什么?如何手写一个call()?Symbol是什么,怎么用Symbol调优?含详细解析_第7张图片

你可能感兴趣的:(JS源码解析,javascript,开发语言,前端)