bind()、call()、apply()理解及用法

bind()、call()、apply()理解及用法

apply和call都是为了改变某个函数运行时的上下文而存在的(就是为了改变函数内部this的指向),Function对象的方法,每个函数都能调用;

使用apply或call方法,其运行的上下文指向第一个参数,apply的第二个参数是一个参数数组,call的第二个及其以后的参数都是数组里面的元素。

apply和call的常用用法:

  1. 数组之间的追加;

    例如:多维数字转一维

     let arr=[1,[7,8],[5,6]];
     res=[].concat.apply([],arr)
  2. 扩充作用域拥有Math的min和max方法,获取数组中的最大值和最小值;

    let numbers = [5, 458 , 120 , -215 ];
    let maxInNumbers = Math.max.apply(Math, numbers), //458

       maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458
    
  3. 验证是否是数组;

    function isArray(obj){

      return Object.prototype.toString.call(obj) === '[object Array]' ;

    }

  4. 让类数组拥有方法;

    比如: arguments对象,获取到的文档节点等,并没有数组的那些方法:

    Array.prototype.slice.apply(argument);
    //理论上来说这个比较快,直接在原型上查找slice方法
    //但实际上比较慢
    或者
    [].slice.apply(arguments);
    //理论上来说这个比较慢,因为要Array做一个实例化再查找slice方法
    //实际上比较快,因为现在的各种自动化工具会把上一种方法转换为这种,而第二种代码比较简洁,所以会比较快;

binde 方法的使用

也是改变函数体内this的指向,bind()是es5中的方法,bind会创建一个新函数,称为绑定函数,当调用这个函数的时候,绑定函数会以创建它时传入bind()方法的第一个参数作为this,传入bind()方法的第二个及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数;
例如:(后面的代码皆取自张鑫旭大神的博客)

var button = document.getElementById("button"),
    text = document.getElementById("text");
    button.onclick = function() {
       alert(this.id); // 弹出text
    }.bind(text);

但由于ie6~ie8不支持该方法,所以若想在这几个浏览器中使用,我们就要模拟该方法,这也是面试常考的问题,模拟的代码如下:

if (!function() {}.bind) {
    Function.prototype.bind = function(context) {
        var self = this;
        var args = Array.prototype.slice.call(arguments);
            
        return function() {
            return self.apply(context, args.slice(1));    
        }
    };
}

上面的代码中this的指向是个容易理解错的地方。

首先,我们判断是否存在bind方法,然后,若不存在,向Function对象的原型中添加自定义的bind方法。

这里面var self = this这段代码让我很困扰,按理说,prototype是一个对象,对象的this应该指向对象本身,也就是prototype,但真的是这样吗。看看下面的代码:

function a(){};

a.prototype.testThis = function(){console.log(a.prototype == this);};

var b = new a();

b.testThis();//false

显然,this不指向prototype,而经过测试,它也不指向a,而指向b。所以原型中的this值就明朗了。指向调用它的对象

Array.prototype.slice.call(arguments);

上面这段代码,它的作用是将一个类数组转化为真正的数组,arguments是传给call的那个上下文(由于arguments自己没有slice方法,这里属于借用Array原型的slice方法)。而且经过测试,若果你不给slice传参数,那就等于传了个0给它,结果就是返回一个和原来数组一模一样的副本。

这之后的代码就很好理解,返回一个函数,该函数把传给bind的第一个参数当做执行上下文,由于args已经是一个数组,排除第一项,将之后的部分作为第二部分参数传给apply,前面讲过apply的用法。

如此,我们自己的这个bind函数的行为就同es5中的bind一样了。

总之三个的使用区别:

  • 都是用来改变函数的this对象的指向的;
  • 第一个参数都是this要指向的对象;
  • 都可以利用后续参数传参;
  • bind是返回对应函数,便于稍后调用,apply、call是立即调用;
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/101085.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 什么叫结构化数据半结构化数据和非结构化数据(xml是非结构化数据)

    计算机信息化系统中的数据分为结构化数据和非结构化数据、半结构化数据。结构化数据结构化数据,是指由二维表结构来逻辑表达和实现的数据,严格地遵循数据格式与长度规范,主要通过关系型数据库进行存储和管理。也称作行数据,一般特点是:数据以行为单位,一行数据表示一个实体的信息,每一行数据的属性是相同的。比如: id name gen…

  • hibernate query_下列关于hibernate说法正确的是

    hibernate query_下列关于hibernate说法正确的是转自品略图书馆:http://www.pinlue.com/article/2020/03/0920/1310003985022.html以前写代码,总免不了编写登陆部分。在获取user的时候,只可能返回一个user实例,或者为null。以前使用以下方法实现。Java代码publicUserget(Stringid){Sessionsession=HibernateU…

  • UDP 流量攻击_网络流量攻击

    UDP 流量攻击_网络流量攻击最近在群里聊天看到有人被UDP攻击我几年前也遇到过当时前任工作交接过来面临很多挑战。话又说回来凡是跳槽或主动找到你的公司都是让你去救火的。先说说UDP攻击原理很简单就是随便连接一个IP地址随便写一个端口号。IP地址存在与否并不重要。这是UDP的特性。然后发送大数据包堵塞交换机路由器。我们在局域网上模拟注意UDP不能在同一个VLAN下…

  • android 杀进程 方法,android中杀死进程的方法

    android 杀进程 方法,android中杀死进程的方法第一种方法:这个方法只能自杀,不能杀死其他进程~/*****************************************************杀死进程的第一种方法******************************…

  • linux定时器编程实验报告,Linux定时器实验.doc[通俗易懂]

    linux定时器编程实验报告,Linux定时器实验.doc[通俗易懂]Linux定时器实验Linux第六次实验及分析报告实验要求:1)在用户态编写一个程序,该程序设定一个定时器,在时间到期的时候做出某种可观察的响应(方法不限)2)分析你的程序的实际执行借助了内核的哪些机制3)提交实验与分析报告一:在用户态编写一个程序,该程序设定一个定时器,在时间到期的时候做出某种可观察的响应(方法不限)G++进行编译运行结果如下:可见调用间隔定时器定时10秒成功!二:分析你的程序的…

  • Django的HttpRequest[通俗易懂]

    Django的HttpRequest[通俗易懂]HttpReqeust对象服务器接收到http协议的请求后,会根据报文创建HttpRequest对象,这个对象不需要我们创建,直接使用服务器构造好的对象就可以。视图的第一个参数必须是HttpRequest对象,在django.http模块中定义了HttpRequest对象的API。属性下面除非特别说明,属性都是只读的。path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分。…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号