• JavaScript中的call、apply 和 bind


    JavaScript中的call、apply 和 bind

    1. Function.prototype.call()

    函数实例的 call 方法,可以指定函数内部的 this 指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数

    一句话概括 call 方法的作用:例如 a.call(obj) ,在 obj 的作用域中运行 a,

    let obj = {};
    let f = function() {
    	return this;
    }
    
    f() === window   // true
    f.call(obj) === obj // true
    
    /*
    	上面代码可以看出,全局环境下运行函数 f,this指向全局环境,call 方法可以改变 this 指向,指定 this 指向 obj,然后在对象 obj     的作用域下运行函数 f
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    call 方法的参数,应该是一个对象。如果参数为空、nullundefined ,则默认传入全局对象

    let n = 123;
    var obj = { n: 456 };
    
    let a = function() {
        console.log(this.n)
    }
    
    a.call() // 123
    a.call(null) // 123
    a.call(undefined) //123
    a.call(window) // 123
    a.call(obj) // 456
    
    /*
    	上面代码中 call 的方法的第一个参数如果是为空、null、undefined 等同于指向全局对象 window(浏览器为 window 对象),所以输出的都是 123
    	call 方法的第一个参数如果是一个对象,则会子 obj 的作用域下调用函数 a ,所以输出 456
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    如果函数第一个参数是一个原始值,那么这个原始值会自动转成对应的包装对象,然后传入 call 方法

    function f() {
        consolelog(this)
    }
    
    f.call(5) // Number{5}
    f.call('a') // String{'a'}
    
    // call 中的第一个参数是一个原始值,会自动转化为包装对象,然后绑定到 this 中
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    call 方法还可以接受多个参数

    第一个参数:所要指向的那个对象

    后面的参数:函数调用时所需的参数

    function add(a,b) {
        return a + b;
    }
    // 第一个参数 this 表示当前环境
    add.call(this,1,2) // 3
    
    /*
    	call 方法指定函数 add 内部的 this 指定到当前环境,并且调用函数 add 时的参数为 1,2。所以返回 3
    */ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2. Function.prototype.appy()

    apply 方法与 call 方法的作用类似,也是改变 this 的指向,然后在调用该函数。唯一的区别就是,apply 接受一个数组作为函数执行的参数,使用格式如下

    func.apply(obj,[arg1, arg2, ...])
    
    • 1

    apply 方法的第一个参数也是 this 所要指向的对象,如果设为 null 或 undefined ,则等同于只想全局对象。第二个参数则是一个数组,该数组中的所有元素依次传入原函数。

    function f(x,y) {
        return x + y;
    }
    
    f.call(null, 1, 2) // 3
    f.apply(null, [1, 2]) // 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3. Function.prototype.bind()

    bind() 方法用于将函数体内的 this 绑定到某个对象,然后返回一个新函数

    function.bind(obj) 在 obj 的环境中运行 function 这个函数(记住这句话) ,相当于obj.function

    let d = new Date()
    d.getTime() // 1658922441747
    
    let p = d.getTime
    /*
    	d.getTime 这个方法的执行上下文是 window
    	换句话说就是:在 window 这个环境中运行 d.getTime,而 window 中没有 getTime 这个方法,所以报错
    */
    p() // this is not a Date object.at getTime ()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    上面代码中将 d.getTime 赋值给 p ,然后调用 p 会报错,这是因为 getTime() 方法内部的 this 绑定 Date 对象实例,赋值给 p 后,内部的 this 已经不在指向 Date 对象实例了

    let p2 = d.getTime.bind(d)
    /*
    	上面那个代码的意思是将 d.getTime 这个方法的执行上下文变为 d,而 d 是一个 Date 实例
    	换句话说就是在 Date 这个环境中运行 d.getTime 这个方法,而 Date 中有这个方法
    */
    p2() // 1658922441747
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    bind() 方法将 getTime 内部的 this 绑定在 d 对象,这时就可以安全的将这个方法复制给其他变量了

    bind() 方法的参数就是所要绑定的 this 对象

    let counter = {
        count: 0,
        inc: function() {
            this.count++
        }
    }
    
    let func = counter.inc.bind(conuter)
    func()
    counter.count // 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    也可以将 this 绑定到其他对象

    let counter = {
        count: 0,
        inc: function() {
            this.count++
        }
    }
    
    let obj = {
        count: 100
    }
    
    let func = counter.inc.bind(obj)  // 在 obj 的环境中运行 counter 里面的 inc 方法
    func()
    obj.count // 101
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    bind() 还可以接受更多的参数,将这些参数绑定到原函数的参数

    let add = function(x,y) {
        return x * this.n + y * this.m
    }
    
    let obj = {
        n: 2,
        m: 2
    }
    
    let newAdd = add.bind(obj,5) // 将 5 传递给 add 函数的 x
    newAdd(6) // 22   2*5+2*6
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    参考文献批量添加上标
    国家开放大学 模拟 试题 训练
    构建一个快速数据分析(boruta+shap+rcs)的shiny APP
    K8s版本升级---v1.21.0至v1.21.12
    笔记本为什么不出可升级CPU的,用台式CPU不行吗?
    springboot+老年康复中心信息管理系统 毕业设计-附源码250859
    ROS中的分布式通信
    ModStart:开源免费的PHP企业网站开发建设管理系统
    UDP单播和组播通讯之C#设计笔记(十四)
    Dockerfile文件解释
  • 原文地址:https://blog.csdn.net/qq_45675616/article/details/126022849