Hand tear bind method

1. Let's take a look at the description and function of bind on MDN
Insert picture description here
Insert picture description here

First of all, we can know that bind is a method on the prototype of the function object Function, so all our custom function objects inherit this method, that is, we can use the bind method.
2. Analyze the role of bind. The
definition and description are more official. Let's take an example to describe the role of bind, so that we can know what kind of requirements we have to write by hand.

  let obj={
    
    
            name:'lisi',
            getName(){
    
    
                return this.name
            }
        }
        let a=obj.getName
      console.log(a())//undefined

First analyze why such a result is output. First, we must first figure out the point of this in the function. Obviously, the above code declares a variable a in the outer layer to point to the getName function, which is now equivalent to let a=function(){ return this. name} and then call the a function. If there is no name attribute in the scope of this function, it will look for the name attribute in the scope of the upper layer. Obviously, there is no name attribute in the window object of the upper layer. So it is undefined. In order to verify our statement, you can add a name attribute to the window, try

   // let name='wangwu'
        window.name='wangwu'
        let obj={
    
    
            name:'lisi',
            getName(){
    
    
                return this.name
            }
        }
        let a=obj.getName
      console.log(a())//   wangwu

The output of wangwu proves that our statement is correct. According to the description of the role of bind, try to call bind, obj.getName.bind(obj), and return a new function. This in this function points to the first parameter is obj, which is now equivalent to let a=obj.getName.bind (obj)=function(){return obj.name}, because this points to obj, we can think that this is obj, the following code

 // let name='wangwu'
        // window.name='wangwu'
        let obj={
    
    
            name:'lisi',
            getName(){
    
    
                return this.name
            }
        }
        let a=obj.getName.bind(obj)
      console.log(a())//   lisi

The output of lisi, see here we should know the use and function of bind.
3. Handwriting bind
In fact, we hand-write some methods, first know how to use these methods, and then use our own code to reproduce the use of it. In order to distinguish, let's define this method as _bind, and then we can use _bind to output lisi as above.
① Like bind, add _bind to the prototype of the function object

 		Function.prototype._bind=function(){
    
    
           
       }
        let obj={
    
    
            name:'lisi',
            getName(){
    
    
                return this.name
            }
        }
        let a=obj.getName._bind(obj)
      console.log(a())//   lisi

② Return a new function and get the first parameter.

  Function.prototype._bind=function(){
    
    
           let firstArg=[].shift.call(arguments)//获取第一个参数
           return function(){
    
    //返回新函数
               
           }
       }
        let obj={
    
    
            name:'lisi',
            getName(){
    
    
                return this.name
            }
        }
        let a=obj.getName._bind(obj)
      console.log(a())//   lisi

③This in the new function points to the first parameter

 Function.prototype._bind=function(){
    
    
           let firstArg=[].shift.call(arguments)
           return function(){
    
    
               return this.apply(firstArg)//新函数里面的this指向第一个参数
           }
       }
        let obj={
    
    
            name:'lisi',
            getName(){
    
    
                return this.name
            }
        }
        let a=obj.getName._bind(obj)
      console.log(a())//   lisi

At this point we can already output lisi, and we have achieved the functions we need.
4. Perfect function The
most important function has been realized. The bind method can pass in parameters when specifying the object. For example, we want to pass in a parameter to getName.

 Function.prototype._bind=function(){
    
    
           let firstArg=[].shift.call(arguments)//第一个参数
           
           let _this=this//调用_bind的函数
           return function(){
    
    
               return _this.apply(firstArg)//调用调用_bind的函数,并将调用_bind的函数的this指向调用_bind时传入的第一个参数
           }
       }
       
        let obj={
    
    
            name:'lisi',
            getName(age){
    
    //要调用的函数有参数
                return this.name+':'+age
            }
        }
        let a=obj.getName._bind(obj,12)//希望绑定的时候传入参数给要调用的函数,这里是getName
      console.log(a())//   lisi:12//希望得到的结果

In fact, I only need to get the parameters when calling _bind and give it to the function that calls _bind.

 Function.prototype._bind=function(){
    
    
           let firstArg=[].shift.call(arguments)//第一个参数
           let args=[].slice.call(arguments)//剩余参数
           let _this=this//调用_bind的函数
           return function(){
    
    
               return _this.apply(firstArg,args)//调用调用_bind的函数,并将调用_bind的函数的this指向调用_bind时传入的第一个参数
           }
       }
       
        let obj={
    
    
            name:'lisi',
            getName(age){
    
    //要调用的函数有参数
                return this.name+':'+age
            }
        }
        let a=obj.getName._bind(obj,12)//希望绑定的时候传入参数给要调用的函数,这里是getName
      console.log(a())//   lisi:12//希望得到的结果

The final output is lisi:12, which meets our expectations. Now there is another requirement. We hope that we can input parameters when calling _bind, or when calling a, that is, when calling a new function. The following code:

  Function.prototype._bind=function(){
    
    
           let firstArg=[].shift.call(arguments)//第一个参数
           let args=[].slice.call(arguments)//剩余参数
           let _this=this//调用_bind的函数
           return function(){
    
    
               return _this.apply(firstArg,args)//调用调用_bind的函数,并将调用_bind的函数的this指向调用_bind时传入的第一个参数
           }
       }
       
        let obj={
    
    
            name:'lisi',
            getName(age,sex){
    
    //要调用的函数有参数
                return this.name+':'+age+':'+sex
            }
        }
        let a=obj.getName._bind(obj,12)//希望绑定的时候传入参数给要调用的函数,这里是getName
      console.log(a('male'))//   lisi:12:male//希望得到的结果

In fact, we put the parameters passed in when calling the new function, that is, a and the parameters passed in when calling _bind before, and then put it in the function that calls _bind, that is, put it in _this.apply( ), the code is as follows

 Function.prototype._bind=function(){
    
    
           let firstArg=[].shift.call(arguments)//第一个参数
           let args=[].slice.call(arguments)//剩余参数
           let _this=this//调用_bind的函数
           return function(){
    
    
               return _this.apply(firstArg,args.concat([].slice.call(arguments)))//调用调用_bind的函数,并将调用_bind的函数的this指向调用_bind时传入的第一个参数
           }
       }
       
        let obj={
    
    
            name:'lisi',
            getName(age,sex){
    
    //要调用的函数有参数
                return this.name+':'+age+':'+sex
            }
        }
        let a=obj.getName._bind(obj,12)//希望绑定的时候传入参数给要调用的函数,这里是getName
      console.log(a('male'))//   lisi:12:male//希望得到的结果

We finally got our results as expected, and now we have implemented bind by hand. The use of the bind method is not complicated. Why do we bother to reimplement the bind method. In fact, we need to understand a lot of things in the process of implementing a small bind, such as function scope, this point, and how to accept it. Parameters, and how we break down the requirements to implement them in code. Understanding of these things has benefited a lot, and it will also help us to read the source code in the future and improve our ability to solve problems.

Guess you like

Origin blog.csdn.net/weixin_44494811/article/details/113776944