zoukankan      html  css  js  c++  java
  • js中的call()和apply()和bind()方法

    call()、apply()、bind()的用法主要是纠正作用域中的this


    1.call()

    语法:obj1.call(obj2[,param1,param2,...])
    定义:用obj2对象来代替obj1,调用obj1的方法。即将obj1应用到obj2上。
    说明:call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 obj2 指定的新对象。 如果没有提供 obj2参数,那么 Global 对象被用作 obj2。

    原理

    Function.prototype.imitateCall = function (context) {
        // 赋值作用域参数,如果没有则默认为 window,即访问全局作用域对象
        context = context || window    
        // 绑定调用函数(.call之前的方法即this,前面提到过调用call方法会调用一遍自身,所以这里要存下来)
        context.invokFn = this    
        // 截取作用域对象参数后面的参数
        let args = [...arguments].slice(1)
        // 执行调用函数,记录拿取返回值
        let result = context.invokFn(...args)
        // 销毁调用函数,以免作用域污染
        Reflect.deleteProperty(context, 'invokFn')
        return result
    }

    2.apply()

    语法:obj1.call(obj2[,arrArg])
    定义:用obj2对象来代替obj1,调用obj1的方法。即将obj1应用到obj2上。

    说明:call ()和apply()作用一样,但是call()可以接收任何类型的参数,而apply()只能接收数组参数。

    作用:这两个函数都是在特定的作用域中调用函数,能改变函数的作用域,实际上是改变函数体内 this 的值 。

    原理

    Function.prototype.imitateApply = function (context) {
        // 赋值作用域参数,如果没有则默认为 window,即访问全局作用域对象
        context = context || window
        // 绑定调用函数(.call之前的方法即this,前面提到过调用call方法会调用一遍自身,所以这里要存下来)
        context.invokFn = this
        // 执行调用函数,需要对是否有参数做判断,记录拿取返回值
        let result
        if (arguments[1]) {
            result = context.invokFn(...arguments[1])
        } else {
            result = context.invokFn()
        }
        // 销毁调用函数,以免作用域污染
        Reflect.deleteProperty(context, 'invokFn')
        return result
    }

    3.基本用法

     function add(a,b){
            return a+b;
        }
        function sub(c,d){
            return c-d;
        }
        function result(){
            this.addValue = null;
            this.subValue = null;
            this.showResult=function(){
                alert(this.addValue);
                alert(this.subValue);
            }
        }   
        function myCallTest(){//此处this指向了add,如果不使用call则this指向window对象
                return add.call(this,7,2);
        }
        var r = new result();
        console.log(myCallTest());//9
        r.addValue = add.call(sub,4,2); //6,将add方法应用到sub上,即sub的指针指向add方法
        r.subValue = sub.call(add,4,2); //2,用add对象替换sub对象,并调用sub对象的方法
        r.showResult(); //在js中函数也是一个Function对象,函数名即是对象引用

    4.继承特性

    function add(a,b){
        return a+b;
    }
    function sub(c,d){
        return c-d;
    }
    function result(){
        this.addValue = null;
        this.subValue = null;
        this.showResult=function(){
            alert(this.addValue);
            alert(this.subValue);
        }
    }
    var r = new result();
    r.addValue = add.call(r,4,2);    //6,r继承add函数的所有特性
    r.subValue = sub.call(r,4,2);    //2,r集成sub函数的所有特性
    r.showResult();    

    5.bind()

    bind()函数也可以改变this指向,但是该函数返回了一个新的函数(绑定函数),当调用绑定函数时,会以bind的第一个参数作为当前作用域的上下文(this),之后的参数则作为原函数的属性。

    var write = document.write;
    write.bind(document)("hello!");

    这里write的this指向global或window,如果直接用write("hello!"),则非法调用(Illegal invocation),因为write的内部指向被修改为了window。所以需要bind重新调整索引,当然用call也可以。

    var write = document.write;
    write.call(document,"hello!");

    对比可以发现: call()、apply()都是立即执行的,bind()则是返回了一个函数,需再次调用才会执行。

    原理:

    Function.prototype.imitateBind = function (context) {
        // 获取绑定时的传参
        let args = [...arguments].slice(1),
            // 定义中转构造函数,用于通过原型连接绑定后的函数和调用bind的函数
            F = function () {},
            // 记录调用函数,生成闭包,用于返回函数被调用时执行
            self = this,
            // 定义返回(绑定)函数
            bound = function () {
                // 合并参数,绑定时和调用时分别传入的
                let finalArgs = [...args, ...arguments]
                
                // 改变作用域,注:aplly/call是立即执行函数,即绑定会直接调用
                // 这里之所以要使用instanceof做判断,是要区分是不是new xxx()调用的bind方法
                return self.call((this instanceof F ? this : context), ...finalArgs)
            }
        
        // 将调用函数的原型赋值到中转函数的原型上
        F.prototype = self.prototype
        // 通过原型的方式继承调用函数的原型
        bound.prototype = new F()
        
        return bound
    }

    转 : https://blog.csdn.net/mafan121/article/details/52922149

    https://www.cnblogs.com/Shd-Study/p/6560808.html

  • 相关阅读:
    java学习(4):第一个Java程序(Hello world)
    java学习(3):字符集和字符编码的区别
    java学习(2):二进制、十进制、原码、反码、补码
    Java学习(1):JRE和JDK
    缓存
    关联表查询
    男0女1
    嵌套查询
    定义别名
    增删改查
  • 原文地址:https://www.cnblogs.com/fps2tao/p/15266772.html
Copyright © 2011-2022 走看看