JavaScript手写系列之call

/**
 * @author      haiyuan.wang
 * @date        2021.04.01
 * @vision      1.0
 * 
 * @description call                                 方法主要的作用是改变函数的执行环境
 * @example     fn.call(thisArg, arg1, arg2, ...)
 * @param       {Object}    thisArg                  必选的。运行时的 this 值,非严格模式下,null 和 undefined 会自动指向 window
 * @param       {*}         arg1, arg2, ...          可选的。执行过程中要传入的参数
 */

// 第一个例子,使用 call 方法调用父构造方法,实现继承
// 基类 Goods
function Goods(goods, amount, price) {
  this.goods = goods
  this.amount = amount
  this.price = price
}
// 子类,继承基类的属性
function Fruit(goods, amount, price) {
  Goods.call(this, goods, amount, price)
}
let fruit = new Fruit('orange', 100, 50)
console.log('fruit :>> ', fruit); // Fruit { goods: 'orange', amount: 100, price: 50 }


// 第二个例子,使用 call 调用函数的,并且指定上下文的 this
let tempObj = {
  language: 'JavaScript',
}
function getLanguage() {
  return this.language
}
console.log(getLanguage.call(tempObj)); // JavaScript

// 实现一个自己的 call 方法
;(function() {
  if(!Function.prototype.myCall) { // 给 Fuction 类的原型上加 myCall 属性
    Function.prototype.myCall = function myCall(context, ...args) {
      let fn = this;      // 谁调用myCall谁就是this,所以this就是原函数
          console.log(fn);    // getLanguage 函数
          if(typeof fn !== 'function') throw TypeError `${fn} is not a funtion` // 如果不是函数,抛出一个类型错误
          let key = Symbol('key') 
          if (typeof context === 'undefined' || context === null) {  // 判断是否是undefined和null
            context = window
          }
          context[key] = fn    // 将 fn 挂在到 context 的属性上,通过 context.fn() 这种形式调用,就实现了改变this(谁调用fn,谁就是this)       
          let result = context[key](...args)
          delete context[key]
          return result
       }
  }
})()
console.log(getLanguage.myCall(tempObj)); // JavaScript
// console.log(/sdf/.myCall(tempObj)); // /sdf/.myCall is not a function
// 复杂数据类型 Object: Date  regExp  function  Array
// 基本数据类型: string number Boolean null undefined

 

posted @ 2021-04-02 09:35  清水渡白吟堤你如风  阅读(121)  评论(0编辑  收藏  举报