美文网首页
apply、call、bind的区别和用法

apply、call、bind的区别和用法

作者: 前端工程狮_jam | 来源:发表于2018-02-21 16:18 被阅读0次

    在js中,call、apply和bind是为了动态改变this而出现的,当一个object没有某个方法(本栗子中other没有say方法),但是其他的有(本栗子中person有say方法),我们可以借助call、apply或bind用其它对象的方法来操作。由此可见,这三种方法都是用来改变函数的this对象的指向的。有共同相似点:1、都是用来改变函数的this对象的指向的2、第一个参数都是this要指向的对象3、都可以继续传递参数

    • 无传参的情况
    var person = {
        name: '小菜',
        gender: '男',
        say: function() {
            console.log(this.name + ',' + this.gender);
        }
    }
    var other = {
        name: 'hathy',
        gender: '女',
    }
    person.say(); // hathy,女
    //如果我们想要用xb的say()方法输出other的数据,要怎么办呢?
    //其实call和apply方法,都是对函数的直接调用,但是bind()方法需要加上()来执行
    person.say.call(other);  //hathy,女
    person.say.apply(other); //hathy,女
    person.say.bind(other)(); //hathy,女
    
    • 带传参的情况,调用参数的形式有区别。标准格式参考:1、func.call(this, arg1, arg2);2、func.apply(this, [arg1, arg2]);3、func.bind(this, arg1, arg2)();
    var person = {
        name: '小菜',
        gender: '男',
        say: function(age, school) {
            console.log(this.name + ',' + this.gender + '---' + age + ',' + school);
        }
    }
    var other = {
        name: 'hathy',
        gender: '女',
    }
    //call()和apply()函数的用法其实是一样的,只是传参的形式不一样,这是他们最大的差别
    //bind()跟call()传参很像,返回的其实还是一个函数,并没有执行
    person.say.call(other, 28, '清华大学');  //hathy,女---28,清华大学
    person.say.apply(other, [27, '北京大学']); //hathy,女---27,北京大学
    person.say.bind(other, 28, '清华大学')(); //hathy,女---28,清华大学
    //定义全局变量
    var name = 'xx';
    var gender = '男';
    //不指定上下文对象,用null代表将执行上下文交回给全局作用域
    person.say.call(null, 28, '清华大学'); //xx,男---28,清华大学
    
    • 某个函数的参数数量是不固定的,因此要说适用条件的话,当你的参数是明确知道数量时用call。而不确定的时候用apply,然后把参数push进数组传递进去。当参数数量不确定时,函数内部也可以通过arguments这个数组来遍历所有的参数。
    //数组之间追加
    var array1 = [12 , "foo" , {name: "Joe"} , -2458]; 
    var array2 = ["Doe" , 555 , 100]; 
    console.log(Array.prototype.push.apply(array1, array2)); //7 == array1.length
    //获取数组中的最大值和最小值
    var numbers = [5, 458 , 120 , -215 ]; 
    var maxInNumbers1 = Math.max.apply(Math, numbers),   //458
        maxInNumbers2 = Math.max.call(Math,5, 458 , 120 , -215); //458
    //验证是否是数组(前提是toString()方法没有被重写过)
    function isArray(obj){ 
        return Object.prototype.toString.call(obj) === '[object Array]';
    }
    console.log(isArray(array1));  //true
    //类(伪)数组使用数组方法
    var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
    //自定义日志方法,内部代理console.log 
    function myLog(){
        var args = Array.prototype.slice.call(arguments);
        args.unshift('(tips)');
        console.log.apply(console, args);
    }
    myLog(1,2);  //(tips) 1 2
    
    • bind函数的理解
    //单体模式中,通常我们会使用_this,that,self等保存this这样我们可以在改变了上下文之后继续引用到它
    var foo = {
        bar: 1,
        eventBind: function() {
            var _this = this;
            document.body.onclick = function() {
                console.log(_this.bar); //1  注意需要设html,body的height为100%
            }
        }
    }
    foo.eventBind();
    //使用bind()可以更加优雅的解决这个问题
    var foo = {
        bar: 1,
        eventBind: function() {
            document.body.onclick = function() {
                /* Act on the event */
                console.log(this.bar); //1
            }.bind(this);
        }
    }
    foo.eventBind();
    //当回调函数被执行的时候,this便指向foo对象。再来一个简单的栗子:
    var other = function() {
        console.log(this.bar);
    }
    other(); // undefined
    var func = other.bind(foo);
    func(); // 1
    //在Javascript中,多次bind()是无效的。更深层次的原因,bind()的实现,相当于使用函数在内部包了一个call/apply,第二次bind()相当于再包住第一次bind(),故第二次以后的bind是无法生效的
    var bar = function() {
        console.log(this.x);
    }
    var foo = {
        x: 3
    }
    var sed = {
        x: 4
    }
    var func = bar.bind(foo).bind(sed);
    func(); //3
    
    var fiv = {
        x: 5
    }
    var func = bar.bind(foo).bind(sed).bind(fiv);
    func(); //3
    
    • 附上bind实现的源码实现,其本质是内部调用apply
    // the .bind method from prototype.js
    Function.prototype.bind = function(){
        var fn = this, args = Array.prototype.slice.call(arguments),object = args.shift();
        return function(){
            return fn.apply(object,args.concat(Array.prototype.slice.call(arguments)));
        }
    }
    

    相关文章

      网友评论

          本文标题:apply、call、bind的区别和用法

          本文链接:https://www.haomeiwen.com/subject/llfgzxtx.html