• JS 的 call apply bind 方法


    js的call apply bind 方法都很常见,目的都是为了改变某个方法的执行环境(context)

    call

    call([thisObj[,arg1[, arg2[,   [,.argN]]]]])

    thisObj
    可选项。将被用作当前对象的对象。
    arg1, arg2, argN ..
    可选项。将被传递方法参数序列。

    如果没设置严格模式 “use strict”

      当thisObj 不存在或 为 undefined 或为 null 或为 this 时,则隐式地指向 全局对象(在浏览器中即为 window)

    第二个参数是一个个值

    apply

    apply([thisObj[,arg1, arg2, argN]])

    apply和call类似,区别只是第二个参数,是一个数组(或类数组)的形式

    bind

    bind(thisArg [, arg1 [, arg2, …]]);

    bind 也是改变某个方法的执行环境,区别也在于第二个参数(也是一个个的参数形式)和“返回值”的特性。

      它将一个func绑定给thisArg的上下文,并传入相应的参数,并以一个新函数的形式返回,以供调用。

    如 func.call(func1,var1,var2,var3)

    对应的apply写法为:func.apply(func1,[var1,var2,var3])

    对应的bind写法为: func.bind(func1,var1,var2,var3)() 

    来举个栗子:

    //'use strict'
    
    var name = 'name1';
    var obj = {
        name: 'name2',
        sayName: function(str1,str2){
            str1 = str1 || '';
            str2 = str2 || '';
            console.log(str1 + this.name + str2);
        }
    };
    
    obj.sayName();
    
    obj.sayName.bind(window,'Hello: ',' !')();
    
    obj.sayName.apply(this,['hello: ',' ,']);
    
    obj.sayName.call(obj,'hello: ',' .');

    将会输出:

    注1:但IE9(包括IE9)以上的才支持bind

    所以,在不支持bind的浏览器上,我们需要模拟一下

    Function.prototype.Bind = function(context){
        var self = this,
                    // 获取到bind第二个参数(中的所有参数)
            args = Array.prototype.slice.call(arguments,1);
            // 返回一个新的函数
        return function(){
            // 将相关参数赋给这个bind所在方法,并将执环境赋给context
            return self.apply(context,args);
        };
    };

    注2:

    Function.prototype的apply和call是在1999年发布的ECMA262 Edition3中才加入的(1998年发布ECMA262 Edition2)。

    在此前的的浏览器如IE5.01(JScript 5.0)中是没有apply和call的。因此也会带来一些兼容性问题。所以,

    call的模拟:

    Function.prototype.Call = function(context){
           // 首先判断所给的context,即call的第一个参数
        context = (context == undefined) ? window : context;
        var temp = [],
            evalStr = '';
            // 最后要形成 一个eval字符串函数调用形式,以供动态执行
        for(var i=1,j=arguments.length; i<j; i++){
            temp.push('arguments[' + i + ']');
        }
            // 给context新增一个方法(拥有this值)
        context._apply = this;
        evalStr = 'context._apply(' + temp.join(',') + ')';
        // console.log(evalStr);
        try{
                   // 执行函数调用
            eval(evalStr);
        }catch(e){
            throw new Error(e.message);
        }finally{
                   // 销毁该属性
            delete obj._apply;
        }
    };

    apply的模拟:

    apply也类似,因为第二个参数是类数组的形式,所以也要变换为数组

    // 第二个参数 args是为了方便使用
    Function.prototype.Apply = function(context,args){
        context = (context == undefined) ? window : context;
        var temp = [],
            evalStr = '';
            // 直接拿第二个参数数组的各个元素再进行组合join(',')
            // 为什么不直接用 arguments[1]呢?
            // 因为此时join也要用到 Array.prototype.join.call ,call又不一定支持
        for(var i=0,j=args.length; i<j; i++){
            temp.push('args[' + i + ']');
        }
        
        context._apply = this;
        evalStr = 'context._apply(' + temp.join(',') + ')';
        // console.log(evalStr);
        try{
            eval(evalStr);
        }catch(e){
            throw new Error(e.message);
        }finally{
            delete obj._apply;
        }
    };

    ok 来看一下对比效果

    Function.prototype.Bind = function(context){
        var self = this,
            args = Array.prototype.slice.call(arguments,1);
        return function(){
            return self.apply(context,args);
        };
    };
    
    Function.prototype.Call = function(context){
        context = (context == undefined) ? window : context;
        var temp = [],
            evalStr = '';
        for(var i=1,j=arguments.length; i<j; i++){
            temp.push('arguments[' + i + ']');
        }
        context._apply = this;
        evalStr = 'context._apply(' + temp.join(',') + ')';
        console.log(evalStr);
        try{
            eval(evalStr);
        }catch(e){
            throw new Error(e.message);
        }finally{
            delete obj._apply;
        }
    };
    
    Function.prototype.Apply = function(context,args){
        context = (context == undefined) ? window : context;
        var temp = [],
            evalStr = '';
        for(var i=0,j=args.length; i<j; i++){
            temp.push('args[' + i + ']');
        }
        
        context._apply = this;
        evalStr = 'context._apply(' + temp.join(',') + ')';
        console.log(evalStr);
        try{
            eval(evalStr);
        }catch(e){
            throw new Error(e.message);
        }finally{
            delete obj._apply;
        }
    };
    
    
    
    var name = 'name1';
    var obj = {
        name: 'name2',
        sayName: function(str1,str2){
            str1 = str1 || '';
            str2 = str2 || '';
            console.log(str1 + this.name + str2);
        }
    };
    
    obj.sayName();
    
    obj.sayName.bind(window,'Hello: ',' !')();
    obj.sayName.Bind(window,'Hello: ',' !')();
    
    obj.sayName.apply(this,['hello: ',' ,']);
    obj.sayName.Apply(this,['hello: ',' ,']);
    
    obj.sayName.call(obj,'hello: ',' .');
    obj.sayName.Call(obj,'hello: ',' .');

  • 相关阅读:
    ubuntu下7z文件的解压
    Ubuntu16 编译源码出错 unsupported reloc 43
    两个超级大整数的相加,相乘
    c++ abcd....等等字符所有不同的非重复组合排布
    C# Java 通用MD5加密
    artDialog-学习课程(三) 参数配置表
    artDialog-学习课程(二)-常用弹出框
    MySQL 查看数据库数据表空间大小
    MySQL Date 函数
    artDialog-学习课程(一)-下载与引用
  • 原文地址:https://www.cnblogs.com/imwtr/p/4765278.html
Copyright © 2020-2023  润新知