[JavaScript] Change the this point of the function - call function, apply function, bind function

JavaScript provides us with some function methods to help us deal with the pointing of this inside the function. The commonly used methods are bind(), call(), apply()

1. call function

The call() method can immediately call a function , and can change the this point of the function .

Usage: fun.call(thisArg,arg1,arg2,…)

  • thisArg: the this value specified when the fun function is running
  • arg1, arg2, ...: other arguments
  • Return value: It is the return value of the fun function, because it is the calling function

So when we want to change the point of this and call this function at the same time, we can use call, such as inheritance .

function Father(uname, age) {
    
    
    this.uname = uname;
    this.age = age;
}

function Son(uname, age) {
    
    
    Father.call(this, uname, age);
}

var son = new Son('xiaoming', 18);
console.log(son.uname); //xiaoming

The Son constructor wants to inherit the properties of the Father constructor. In the Son constructor, the Father constructor is called, and at the same time, the this point is changed to point to the Son constructor. This time the call function is used.

The process of realizing inheritance: create an instantiated object son of Son, and then pass 'xiaoming' and 18 to uname and age in function Son(uname, age) respectively, at this time the formal parameter uname='xiaoming'; age= 18; Then there is a function Father.call(this, uname, age) in function Son(uname, age), where uname and age are formal parameters, so they also have corresponding values ​​at this time, and then the first parameter is changed to For this, this in the Son constructor should point to its instantiated object, which is the son here. Call the Father function with these three parameters, that is, the uname attribute of son is assigned the value 'xiaoming' of the formal parameter uname, and the attribute of son is assigned the value 18 of the formal parameter age. Inheritance is implemented.

Two, apply function

The apply() method can call a function immediately , and can change the this point of the function .

How to use: fun.apply(thisArg,[argsArray])

  • thisArg: the this value specified when the fun function is running
  • [argsArray]: passed value, array or pseudo-array form
  • Return value: It is the return value of the fun function, because it is the calling function

Because the parameter it passes in is an array , we can use it to deal with some array-related problems , such as borrowing Math.max() to find the maximum/minimum value of the array.

var arr = [15, 6, 9, 33];
   	var max = Math.max.apply(Math, arr); //max = 33;
   	var min = Math.min.apply(Math, arr); //min = 6;

Math.max is a method (function), and the apply method is used for it. There is no need to change the this point here, so the first parameter lets it point back to Math, and the second parameter can be passed in to the array to be processed. In this way, you can use the Math method to process the array.

The apply method will automatically process the incoming array into the corresponding data type.

Three, bind function

The bind function does not call the function directly , but it can change the this pointer inside the function , which is widely used.

How to use: fun.bind(thisArg,arg1,arg2,…)

  • thisArg: the this value specified when the fun function is running
  • arg1, arg2, ...: other arguments
  • Return value: a copy of the original function modified by the specified this value and initialization parameters , that is to say, the return value is a function

Therefore, when we just want to change the this point and do not want to call this function immediately, we can use bind, such as changing the this point of the timer .

For example, there is a requirement that after a button is clicked, the button is disabled and returns to normal after 2 seconds. Here the this in the timer points to the window, and we want it to point to the currently clicked button, so we need to modify the this point, but we don't want it to be called immediately, but to wait until the condition of the timer is met. So use the bind function .

There is a very clever point here, so this in function () { this.disabled = false; }.bind(this) is already outside the timer, so it no longer points to window, and the environment outside the timer is The button click event means that this points to the currently clicked btn, and through the bind function, the this point of the timer function is cleverly changed to the currently clicked btn to realize the current function.

<body>
    <button>点击</button>
    <button>点击</button>
    <button>点击</button>
    <script>
        var btns = document.querySelectorAll('button');
        for (var i = 0; i < btns.length; i++) {
      
      
            btns[i].addEventListener('click', function () {
      
      
                this.disabled = true;
                setTimeout(function () {
      
      
                    this.disabled = false;
                }.bind(this), 2000);
            })
        }
    </script>
</body>

Another example is the object-oriented Tab column [JavaScript] object-oriented tab column paging switching case we wrote before. At that time, in order to use the global this, a that was defined outside the class, and this was saved first for later use. Great, you need to always remember to define a that. We can try to use the bind function to optimize it instead of defining a new variable that. Take the toggleTab function as an example.

Original code:

var that;
class Tab {
    
    
    //传入要做Tab栏的元素的id
    constructor(id){
    
    
    that = this;
        //获取元素
        this.main = document.getElementById(id);
        this.ul=this.main.querySelector('.tab_list ul:first-child');
        this.con=this.main.querySelector('.tab_con');
        this.add=this.main.querySelector('.tabAdd');
        this.init();
    }
    //初始化函数
    init(){
    
    
        this.update();
        //绑定事件
        this.add.addEventListener('click',this.addTab);
    }
    //切换功能
    toggleTab(){
    
    
        that.clearStyle();
        this.className='current';
        that.sections[this.dataIndex].className='item';
    }
    //清除样式 排他思想
    clearStyle(){
    
    
        for(var i=0;i<this.lis.length;i++){
    
    
            this.lis[i].className='';
            this.sections[i].className='';
        }
    }
    //更新li和section
    update(){
    
    
        //重新获取lis和sections和guanbiBtns
        this.lis = this.ul.querySelectorAll('li');
        this.sections=this.con.querySelectorAll('section');
        this.guanbiBtns=this.main.querySelectorAll('.tab_list .guanbi-btn');
        this.spans=this.ul.querySelectorAll('li span:first-child');

        //重新绑定事件
        for(var i = 0;i<this.lis.length; i++){
    
    
            this.lis[i].dataIndex=i;
            this.lis[i].addEventListener('click', this.toggleTab);
            this.spans[i].addEventListener('dblclick',this.editTab);
            this.sections[i].addEventListener('dblclick',this.editTab);
            this.guanbiBtns[i].addEventListener('click',this.removeTab);
        }
    }
}

The caller of the toggleTab function is a li, so this in the toggleTab function points to the called li, and we need to use the lis of the entire tab element. Consider changing the this point, and this function is not executed immediately, but clicked The event is executed, so use the bind function . But here also needs to use its own this, so you can't directly change the this point, so this.className='current'; there is a problem, how to keep two different this?

The bind function can pass multiple parameters, the first parameter is the this point, we keep it unchanged (because it will be used), and the second parameter is passed in this pointing to the entire tab element . The toggleTab function uses a that to take over the second parameter, so that this can be used to point to the entire tab element.

Other add functions and delete functions are similar, just make corresponding changes.

Optimized code:

class Tab {
    
    
    //传入要做Tab栏的元素的id
    constructor(id){
    
    
        //获取元素
        this.main = document.getElementById(id);
        this.ul=this.main.querySelector('.tab_list ul:first-child');
        this.con=this.main.querySelector('.tab_con');
        this.add=this.main.querySelector('.tabAdd');
        this.init();
    }
    //初始化函数
    init(){
    
    
        this.update();
        //绑定事件
        this.add.addEventListener('click',this.addTab.bind(this.add,this));
    }
    //切换功能
    toggleTab(that){
    
    
        that.clearStyle();
        this.className='current';
        that.sections[this.dataIndex].className='item';
    }
    //清除样式 排他思想
    clearStyle(){
    
    
        for(var i=0;i<this.lis.length;i++){
    
    
            this.lis[i].className='';
            this.sections[i].className='';
        }
    }
    //更新li和section
    update(){
    
    
        //重新获取lis和sections和guanbiBtns
        this.lis = this.ul.querySelectorAll('li');
        this.sections=this.con.querySelectorAll('section');
        this.guanbiBtns=this.main.querySelectorAll('.tab_list .guanbi-btn');
        this.spans=this.ul.querySelectorAll('li span:first-child');

        //重新绑定事件
        for(var i = 0;i<this.lis.length; i++){
    
    
            this.lis[i].dataIndex=i;
            //bind函数优化///
            this.lis[i].addEventListener('click', this.toggleTab.bind(this.lis[i],this));
            this.spans[i].addEventListener('dblclick',this.editTab);
            this.sections[i].addEventListener('dblclick',this.editTab);
            this.guanbiBtns[i].addEventListener('click',this.removeTab.bind(this.guanbiBtns[i],this));
        }
    }
}

Four. Summary

Same point:

  • can change the this point inside the function

difference:

  • call and apply will call the function immediately, and the return value is the return value after the function is executed
  • bind will not call the function immediately, the return value is a function, and the modified copy of the original function
  • The parameters passed by call and bind are the new this pointer and other parameters of the original function, and the parameters passed by apply are the new this pointer and an array

Main application scenarios

  • call() often implements inheritance
  • apply() often deals with array-related issues, such as finding the maximum or minimum value of an array with the help of a Math object
  • bind() does not call the function, but still wants to change the this point, such as changing the this point inside the timer

Guess you like

Origin blog.csdn.net/weixin_43790653/article/details/123672205