• Javascript中改变函数内部this指向的方法:call()、apply()、bind()


    在整理Javascript中改变函数内部this指向的方法之前,先介绍一下不同函数的调用方式以及函数内this的指向。

    一、函数的调用方式

    1. 普通函数
    2. 对象的方法
    3. 构造函数
    4. 绑定事件函数
    5. 定时器函数
    6. 立即执行函数
    1. <script>
    2. // 函数的调用方式
    3. // 1. 普通函数
    4. function fn() {
    5. console.log('人生的巅峰');
    6. }
    7. // 调用函数
    8. // fn(); fn.call();
    9. // 2. 对象的方法
    10. var o = {
    11. sayHi: function() {
    12. cconsole.log('人生的巅峰');
    13. }
    14. }
    15. // 调用函数
    16. o.sayHi();
    17. // 3. 构造函数
    18. function Star() {};
    19. // 调用函数
    20. new Star();
    21. // 4. 绑定事件函数
    22. btn.onclick = function() {}; // 点击了按钮就可以调用这个函数
    23. // 5. 定时器函数
    24. setInterval(function() {}, 2000); // 这个函数是定时器自动2秒钟调用一次
    25. // 6. 立即执行函数
    26. //第一种写法
    27. (function() {
    28. console.log('人生的巅峰');
    29. })();
    30. //第二种写法
    31. (function() {
    32. cconsole.log('人生的巅峰');
    33. }());
    34. // 立即执行函数是自动调用
    35. script>

    二、函数内this的指向

    • this指向,是当我们调用函数的时候确定的,调用方式的不同决定了this的指向不同,一般我们指向我们的调用者。

    三、改变函数内部this指向

    • JavaScript 为我们专门提供了一些函数方法来帮我们处理函数内部 this 的指向问题,常用的有 bind()call()apply()三种方法。

    3.1、call()方法

    call()方法可以立即调用一个函数,并可以改变该函数的this指向

    使用方法: fun.call(thisArg,arg1,arg2,…)

    • thisArg: 在 fun 函数运行时指定的 this 值
    • arg1,arg2,…: 其他参数
    • 返回值: 就是fun函数的返回值,因为它就是调用函数

    因此当我们想改变 this 指向,同时想调用这个函数的时候,可以使用 call,比如继承。
     

    Son构造函数想继承Father构造函数的属性,在Son构造函数中,调用Father构造函数,同时改变this指向,让其指向Son构造函数。这个时候用到了call函数。

    实现继承的过程: 创建一个Son的实例化对象son,这时把‘xiaoming’,18分别传给function Son(uname, age)中的uname,age,此时形参uname=‘xiaoming’; age=18; 然后function Son(uname, age)中有一个函数Father.call(this, uname, age),这里的uname和age就是形参,所以他们此时也有了对应的值,然后第一个参数改为this,Son构造函数里面的this应该指向它的实例化对象,也就是这里的son。带着这三个参数去调用Father函数,也就是son的uname属性赋值为形参uname的值‘xiaoming’,son的属性赋值为形参age的值18。实现了继承。

    3.2、apply()方法

    apply()方法可以立即调用一个函数,并可以改变该函数的this指向

    使用方法: fun.apply(thisArg,[argsArray])

    • thisArg: 在 fun 函数运行时指定的 this 值
    • [argsArray]: 传递的值,数组或伪数组形式
    • 返回值: 就是fun函数的返回值,因为它就是调用函数

    因为它传入的参数是一个数组,所以我们可以用它处理一些和数组有关的问题,比如借用Math.max()求数组的最大值/最小值。

    1. <script>
    2. // 改变函数内this指向 js提供了三种方法 call() apply() bind()
    3. // 2. apply() 应用 运用的意思
    4. var o = {
    5. name: 'andy'
    6. };
    7. function fn(arr) {
    8. console.log(this);
    9. console.log(arr); // 打印出来的不是数组,而是字符串pink
    10. }
    11. fn.apply(o, ['pink']);
    12. // 1. 第一个也是调用函数 第二个可以改变函数内部的this指向
    13. // 2. 但是它的参数必须是数组(伪数组)
    14. // 3. apply 的主要应用 比如说我们可以利用 apply 借助于数学内置对象求最大值
    15. // Math.max();
    16. var arr = [1, 66, 3, 99, 4];
    17. // var max = Math.max.apply(null, arr);
    18. var max = Math.max.apply(Math, arr);
    19. var min = Math.min.apply(Math, arr);
    20. console.log(max, min);
    21. // 如果传递的数组里面是字符串型的,打印出来的就是字符串型的;如果传递的数组里面是数字型的,打印出来的就是数字型的
    22. script>

    Math.max是一个方法(函数),对其使用apply方法,这里不需要改变this指向,所以第一个参数让它指回Math,第2个参数传入要处理的数组即可。这样就可以借用Math方法处理数组了。

    apply方法会自动将传入的数组处理为对应的数据类型。

    3.3、bind()方法

    bind函数不会直接调用函数,但是可以改变函数内部的this指向,应用非常广泛。

    使用方法: fun.bind(thisArg,arg1,arg2,…)

    • thisArg: 在 fun 函数运行时指定的 this 值
    • arg1,arg2,…: 其他参数
    • 返回值: 由指定的 this值和初始化参数改造的原函数拷贝,也就是说返回值是一个函数

    因此当我们只是想改变 this 指向,并不想立即调用这个函数的时候,可以使用bind,比如改变定时器的this指向

    比如有一个需求,点击某个按钮后,按钮被禁用,2秒后恢复正常。这里定时器里面的this指向的是window,而我们想让它指向当前被点击的button,因此需要修改this指向,但是我们又不希望它立即调用,而是等到满足定时器的条件后才执行,所以要用到bind函数

    这里有一个很巧妙的点,所以function () { this.disabled = false; }.bind(this) 中this已经在定时器的外面了,所以他不再是指向window,而定时器外面的环境是按钮点击事件,也就是说this指向的是当前点击的btn,而通过bind函数,巧妙的把定时器函数的this指向改成了当前点击的btn,就可以实现当前功能。

    1. <body>
    2. <button>点击button>
    3. <button>点击button>
    4. <button>点击button>
    5. <script>
    6. // 3. bind()
    7. var o = {
    8. name: 'andy'
    9. };
    10. function fn(a, b) {
    11. console.log(this);
    12. console.log(a + b);
    13. };
    14. var f = fn.bind(o, 1, 2);
    15. f(); // 3
    16. // 1. 不会调用原来的函数 可以改变原来函数内部的this 指向
    17. // 2. 返回的是原函数改变this之后产生的新函数
    18. // 3. 如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向 此时用bind
    19. // 4. 我们有一个按钮,当我们点击了之后,就禁用这个按钮,3秒钟之后开启这个按钮
    20. // var btn1 = document.querySelector('button');
    21. // btn1.onclick = function() {
    22. // this.disabled = true; // 这个this 指向的是 btn 这个按钮
    23. // // var that = this; // 方法1
    24. // setTimeout(function() {
    25. // 定时器函数里面的this 指向的是window
    26. // // that.disabled = false; // 方法1
    27. // 方法2:用bind()改变this指向,bind在setTimeout函数的外面
    28. // this.disabled = false; // 此时定时器函数里面的this 指向的是btn
    29. // }.bind(this), 3000); // 这个this 指向的是btn 这个对象
    30. // }
    31. var btns = document.querySelectorAll('button');
    32. for (var i = 0; i < btns.length; i++) {
    33. btns[i].onclick = function() {
    34. this.disabled = true;
    35. setTimeout(function() {
    36. this.disabled = false;
    37. }.bind(this), 3000);
    38. }
    39. }
    40. script>
    41. body>

    3.4、call()、apply()、bind() 总结

    相同点:

    • 都可以改变函数内部的 this指向

    不同点:

    • call apply  会立即调用函数,返回值就是函数执行后的返回值,并且改变函数内部的this指向
    • call apply 传递的参数不一样,call 传递参数,apply 必须数组形式
    • bind 不会立即调用函数,返回值是一个函数,改造后的原函数拷贝,可以改变函数内部this指向
    • bind 是返回对应函数,便于稍后调用;apply call 则是立即调用
    • call bind 传递的参数为新的this指向和原函数的其他参数,apply 传递的参数为新的this指向和一个数组

    主要应用场景:

    • call 经常做继承
    • apply 经常跟数组有关系,比如借助于数学对线实现数组最大值与最小值
    • bind 不调用函数,但是还想改变this指向,比如改变定时器内部的this指向
  • 相关阅读:
    Linux网络编程-网络基础1
    在windows10上怎么安装Kafka
    袋鼠云产品功能更新报告01期丨用诚心倾听您的需求
    数字水印技术介绍
    多目标鲈鱼优化算法(Matlab代码实现)
    MySQL 8.0新的GTID持久化线程和GTID恢复方式
    等精度频率计的设计与验证
    【FastAPI】实现服务器向客户端发送SSE(Server-Sent Events)广播
    React-hook-form-mui(五):包含内嵌表单元素的表单
    指定编码“gbk“,防止中文字符乱码
  • 原文地址:https://blog.csdn.net/DIUDIUjiang/article/details/126500855