手写call,apply,bind 方法

8,手写call函数

call函数的实现步骤:

  • 1,判断调用对象是否为函数,即使我们是定义在函数原型上的,但是可能出现使用call等方式进行调用的情况
  • 2,判断传入的上下文对象是否存在,如果不存在,就设置为window
  • 3,处理传入的参数,截取第一个参数后的所有参数
  • 4,将函数作为上下文对象的一个属性
  • 5,使用上下文对象来调用这个方法,并保存返回结果
  • 6,删除刚才新增的属性
  • 7,返回结果
<script>
    // 算法:
          Function.prototype.myCall = function(context){
               // 判断调用对象
               if(typeof this !== 'function'){
                    console.error('type error')
               }
               // 获取参数
               let args = [...arguments].slice(1),result = null
               // 判断context是否传入,如果未传入,则设置为window
               context = context || window
               // 将调用函数设置为对象的方法
               context.fn = this
               // 调用函数
               result = context.fn(...args)
               // 将属性删除
               delete context.fn
               return result
          }
// 测试:
          var obj = {
               name:'123'
          }
          function show(a){
               console.log(this) 
               console.log(a)
          }
          show.myCall(obj,2) // 输出obj,2
     </script>

9,手写apply函数

步骤:

  • 判断调用对象是否为函数,即使是定义在函数的原型上的,但是可能出现使用call等方式调用的情况
  • 判断传入上下文对象是否存在,如果不存在,就设置为window
  • 将函数作为上下文对象的一个属性
  • 判断参数值是否传入
  • 使用上下文对象来调用这个方法,并保存返回结果
  • 删除刚才新增的属性
  • 返回结果

**具体流程和call函数类似,就是在参数处理方式上有所不同。**apply的实现在于第二个参数是数组,而call的参数是一个个排下去的。

Function.prototype.myApply= function(context){
               if(typeof this !== 'function'){
                    throw new TypeError('Error')
               }
               let result = null
               context = context || window
               context.fn = this
               // 判断参数是否存在
               if(arguments[1]){
                    result = context.fn(...arguments[1])
               }else{
                    result = context.fn()
               }
               result = context.fn(args)
               delete context.fn
               return result
          }

10,手写bind函数

bind和apply,call不同的地方

因为bind转换后的函数可以作为构造函数使用,此时this应该指向构造出的实例,而不是bind绑定的第一个参数

bind返回的一个函数,对于函数来说有两种方式调用,一种是直接调用,另一种是通过new的方式

直接调用:直接选择apply的方式,但是对于参数需要注意:f.bind(obj,1)(2),bind可以实现类似的代码,因此需要将两边的参数拼接起来。

new的方式:先判断this,对于new,不会被任何方式改变this,对于这种情况我么需要忽略传入的this。

实现步骤:

  • 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用call等方式调用
  • 保存当前函数的引用,获取其余传入参数值
  • 创建一个函数返回
  • 函数内部使用apply来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的this给apply调用,其余情况都传入指定的上下文对象。
<script>
          Function.prototype.myBind = function(context){
               if(typeof this !=='function'){
                    throw new TypeError('error')
               }
               // 获取参数
               let args = [...arguments].slice(1),fn = this
               return function Fn(){
                    // 根据调用方式,返回不同的值
                    return fn.apply(
                         this instanceof Fn ? this : context,args.concat(...arguments)
                    )
               }
          }
     </script>

// 用法:
function fn1(){
    console.log(this.name)
}
let obj = {
    name :1
}
const fn2 = fn1.myBind(obj)
fn2() // 输出为1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值