zoukankan      html  css  js  c++  java
  • 一起手写吧!call、apply、bind!

    apply,call,bind都是js给函数内置的一些api,调用他们可以为函数指定this的执行,同时也可以传参。

    call

    call 接收多个参数,第一个为函数上下文也就是this,后边参数为函数本身的参数。

    let obj = {
        name: "一个"
    }
    
    function allName(firstName, lastName) {
        console.log(this)
        console.log(`我的全名是“${firstName}${this.name}${lastName}”`)
    }
    // 很明显此时allName函数是没有name属性的
    allName('我是', '前端') //我的全名是“我是前端”  this指向window
    allName.call(obj, '我是', '前端') //我的全名是“我是一个前端” this指向obj

    apply

    apply接收两个参数,第一个参数为函数上下文this,第二个参数为函数参数只不过是通过一个数组的形式传入的。

    allName.apply(obj, ['我是', '前端'])//我的全名是“我是一个前端” this指向obj

    bind

    bind 接收多个参数,第一个是bind返回值是一个函数上下文的this,不会立即执行。

            let obj = {
                name: "一个"
            }
    
            function allName(firstName, lastName, flag) {
                console.log(this)
                console.log(`我的全名是"${firstName}${this.name}${lastName}"我的座右铭是"${flag}"`)
            }
            allName.bind(obj) //不会执行
            let fn = allName.bind(obj)
            fn('我是', '前端', '好好学习天天向上')
    
            // 也可以这样用,参数可以分开传。bind后的函数参数默认排列在原函数参数后边
            fn = allName.bind(obj, "你是")
            fn('前端', '好好学习天天向上')

     

    实现call

    1.call主要都做了些什么。

    • 更改this指向
    • 函数立刻执行

    2.简单实现

    Function.prototype.myCall = function(context) {
      context.fn = this;
      context.fn();
    }
    
    const obj = {
      value: 'hdove'
    }
    
    function fn() {
      console.log(this.value);
    }
    
    fn.myCall(obj); // hdove

    3.出现的问题

    • 1.无法传值
    • 2.如果fn()有返回值的话,myCall 之后获取不到
    Function.prototype.myCall = function (context) {
        context.fn = this;
        context.fn();
    }
    
    const obj = {
        value: 'hdove'
    }
    
    function fn() {
        return this.value;
      }
    
    console.log(fn.myCall(obj));
    • 3.call其实就是更改this指向,指向一个Object,如果用户传的是基本类型又或者干脆就不传呢?
    • 4.myCall执行之后,obj会一直绑着fn()

    4.统统解决

    Function.prototype.myCall = function(context) {
      // 1.判断有没有传入要绑定的对象,没有默认是window,如果是基本类型的话通过Object()方法进行转换(解决问题3)
      var context = Object(context) || window;
      
      /**
        在指向的对象obj上新建一个fn属性,值为this,也就是fn()
        相当于obj变成了
        {
            value: 'hdove',
            fn: function fn() {
              console.log(this.value);
            }
        }
      */
      context.fn = this;
      
      // 2.保存返回值
      let result = '';
      
      // 3.取出传递的参数 第一个参数是this, 下面是三种截取除第一个参数之外剩余参数的方法(解决问题1)
      const args = [...arguments].slice(1);
      //const args = Array.prototype.slice.call(arguments, 1);
      //const args = Array.from(arguments).slice(1);
      
      // 4.执行这个方法,并传入参数 ...是es6的语法用来展开数组
      result = context.fn(...args);
      
      //5.删除该属性(解决问题4)
      delete context.fn;
      
      //6.返回 (解决问题2)
      return result;
    }
    
    
    const obj = {
      value: 'hdove'
    }
    
    function fn(name, age) {
      return  {
          value: this.value,
          name,
          age
      }
    }
    
    fn.myCall(obj, 'LJ', 25); // {value: "hdove", name: "LJ", age: 25}

    二、手动实现Apply

    实现了call其实也就间接实现了apply,只不过就是传递的参数不同

    Function.prototype.myApply = function (context, args) {
        var context = Object(context) || window;
    
        context.fn = this;
    
        let result = '';
    
        //4. 判断有没有传入args
        if (!args) {
            result = context.fn();
        } else {
            result = context.fn(...args);
        }
    
        delete context.fn;
    
        return result;
    }
    
    
    const obj = {
        value: 'hdove'
    }
    
    function fn(name, age) {
        return {
            value: this.value,
            name,
            age
        }
    }
    
    fn.myApply(obj, ['LJ', 25]); // {value: "hdove", name: "LJ", age: 25}

    三、实现Bind

    bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用(MDN)

    bind和apply的区别在于,bind是返回一个绑定好的函数,apply是直接调用.其实想一想实现也很简单,就是返回一个函数,里面执行了apply上述的操作而已.

    不过有一个需要判断的点,因为返回新的函数,要考虑到使用new去调用,并且new的优先级比较高,所以需要判断new的调用,还有一个特点就是bind调用的时候可以传参,调用之后生成的新的函数也可以传参,效果是一样的,所以这一块也要做处理

    因为上面已经实现了apply,这里就借用一下,实际上借用就是把代码copy过来

    Function.prototype.myBind = function (context, ...args) {
        const fn = this
        args = args ? args : []
        return function newFn(...newFnArgs) {
            if (this instanceof newFn) {
                return new fn(...args, ...newFnArgs)
            }
            return fn.apply(context, [...args,...newFnArgs])
        }
    }
  • 相关阅读:
    LAMP动态网站安装脚本
    图片上传
    如何用qq代理发送邮件
    初识c#
    Eclipse使用技巧
    maven中 install的install:install的区别
    Git的各种状态
    phpStorm中Structure窗口中的符号代表的意思
    Apache+PHP+MySQL+phpMyAdmin+WordPress搭建
    Session重点整理
  • 原文地址:https://www.cnblogs.com/magicg/p/12726831.html
Copyright © 2011-2022 走看看