博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
call,apply and bind in JavaScript
阅读量:6436 次
发布时间:2019-06-23

本文共 3406 字,大约阅读时间需要 11 分钟。

call,apply and bind in JavaScript

在ECMAScript中,每个函数都包含两个继承而来的方法:apply() 和 call(),这两个方法的用途都是在特定的作用域中调用函数,主要作用跟bind一样,用来改变函数体内this的指向,或者说是在函数调用时改变上下文。

文章尽量使用大量实例进行讲解,它们的使用场景。同时,也会由浅入深的引导出一些理论,毕竟这几个常用方法,在MDN上都能找到合理的解释

基本功能

改变this的指向

var fruit = {    fruitName:"apple"  }  function getFruit() {    console.log("I like "+this.fruitName)  }  getFruit();    // log   I like undefined  getFruit.call(fruit)    // log   I like apple  getFruit.apply(fruit)   // log   I like apple  var newBind = getFruit.bind(fruit)  newBind();              // log   I like apple

当 getFruit 并非作为一个对象的属性,而是直接当做一个函数来调用,里面的this就会被绑定到全局对象上,即window上, 所以直接调用 getFruit,里面的this指向了全局对象上,返回 undefined

在严格模式下,函数被调用后,里面的this默认是 undefined

后面,通过调用函数上的callapply方法,该变this指向,函数里面的this指向fruit

区别:

bind同样实现了改变this指向的功能,但是它不会立即执行,而是会重新创建一个绑定函数,新函数被调用时,使用bind()方法里面的第一个参数作为this

接受参数

这三个方法,从接受的第二参数开始,都直接传递给函数,但是接受参数的方法却很大的不同。

call,从第二个参数开始,以参数列表的形式展示,

apply,则把传递的函数参数,放在一个数组里面作为第二个参数。

fn.call(obj,arg1,arg2);fn.apply(obj,[arg1,arg2])

bind,从第二个参数开始,同样以参数列表的形式,但是会提前放在新绑定函数的参数之前

var foo = function(name,age){   console.log("name: "+name+"- age: "+age) } var p1 = foo.bind(this,"popo");   // "popo" 作为新函数的第一个参数。 p1(13);                       // logs    name: popo- age: 13 p1("bobo",14)                 // logs    name: popo- age: bobo

应用场景

  • 绑定事件回调中

    $('.div-class').on('click',function(event) {        /*TODO*/        }.bind(this));      }  }

    通常,我们在改变函数上下文之前,都会使用类似that = this,或者self,_this,来把this赋值给一个变量。利用.bind(),可以传入外层的上下文。

  • 循环回调

    循环中利用闭包来处理回调

    for(var i = 0;i < 10;i++){ (function(j){     setTimeout(function(){                     console.log(j);     },600); })(i)}

    每次循环,都会产生一个立即执行的函数,函数内部的局部变量j保存不同时期i的值,循环过程中,setTimeout回调按顺序放入消息队列中,等for循环结束后,堆栈中没有同步的代码,就去消息队列中,执行对应的回调,打印出j的值。

    同理,可以利用bind,每次都创建新的函数,并且已经预先设置了参数,传入不同的指针

    function func(i) {    console.log(i)  }  for(var i =0 ;i< 10;i++) {    setTimeout(func.bind(null,i),600)  }
  • 实现继承

    var Person = function(name,age) {   this.name = name;   this.age = age; } var P1 = function(name,age) {   // 借用构造函数的方式实现继承   // 利用call 继承了Person   Person.call(this,name,age) } P1.prototype.getName = function() {   console.log("name: "+this.name+", age: "+this.age); } var newPerson = new P1("popo",20);   // logs name: popo, age: 20 newPerson.getName();

    实质上,可以看成通过call()或者apply()方法,在即将新建的对象,即这里的newPerson上,执行超类型的构造函数,分别在当前上下文this上添加nameage属性。

  • 数组验证的终极方法

    function isArray(value) {    return Object.prototype.toString.call(value) == "[object Array]"  }

    借用了Object原生的toString()方法,打印出对应变量的构造函数名,

  • 类数组转换为数组

    // 实现一个简单的数组 'unshift'方法  Array.prototype.unshift = function(){    this.splice.apply(this,      [0,0].concat(Array.prototype.slice.apply(arguments)));      return this.length;  }

    首先,利用this.splice.apply(),其中splice,可以直接从数组中移除或者插入变量。apply()则以数组的形式传递参数,需要利用concat拼接数组。

    当函数被调用时,在函数内部会得到类数组arguments,它拥有一个length属性,但是没有任何数组的方法。所以,将slice方法中的this指向arguments,获取到arguments的长度,从而确定方法的startend下标,得到一个数组变量。

    同样适用的还有,DOM里面的NodeList对象,它也是一种类数组对象。

深入理解

实现bind 方法

bind方法在ECMAScript5里面被引入,前面提到过,调用该方法时,返回一个新的函数,可以简单使用下面方法实现其改变this指向的功能。

Function.prototype.bind = function(scope) {    var fn = this;    return function() {      return fn.apply(scope)    }  }

接着,就可以利用concat把bind传递的预置参数拼接到新函数的参数列表中。

Function.prototype.bind = function(scope) {      var args = Array.prototype.slice.call(arguments,1)      var fn = this      return function() {        return fn.apply(scope,args.concat(Array.prototype.slice.call(arguments)))      }   }

参考链接

转载地址:http://cohga.baihongyu.com/

你可能感兴趣的文章
oracle数据库的启动和停止
查看>>
《LoadRunner没有告诉你的》之七——使用 LoadRunner 连续长时间执行测试,如何保证参数化的数据足够又不会重复?...
查看>>
python easy_install django 安装
查看>>
读《图解HTTP》总结--第六章
查看>>
毕业就能拿到上万薪资的程序员他们都做了啥?
查看>>
最小的k个数
查看>>
iOS技巧之获取本机通讯录中的内容,解析通讯录源代码
查看>>
程序员从零到月薪15K的转变,python200G资料分享
查看>>
DNS域名解析的知识了解
查看>>
部署社交网站
查看>>
CentOS下如何修改主机名
查看>>
“机器人商店”是什么?卖机器人的吗?
查看>>
SVN的代码正确提交方法
查看>>
js框架 vue
查看>>
tomcat关闭时进程未退出
查看>>
Git分支管理策略
查看>>
kali安装软件遇到的问题&解决
查看>>
Azure系列2.1.10 —— CloudBlobClient
查看>>
【04-20】httpclient处理302重定向问题
查看>>
OpenGLes2.0 什么是Pbuffer
查看>>