如何理解和熟练运用js中的call及call apply bind

»»深入浅出 妙用Javascript中apply、call、bind
  网上文章虽多,大多复制粘贴,且晦涩难懂,我希望能够通过这篇文章,能够清晰的提升对apply、call、bind的认识,并且列出一些它们的妙用加深记忆。
 apply、call&
  在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。
  JavaScript 的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。
  先来一个栗子:
function fruits() {}
fruits.prototype = {
color: &red&,
say: function() {
console.log(&My color is & + this.color);
var apple =
apple.say();
//My color is red
  但是如果我们有一个对象banana= {color : &yellow&}&,我们不想对它重新定义 say 方法,那么我们可以通过 call 或 apply 用 apple 的 say 方法:
banana = {
color: &yellow&
apple.say.call(banana);
//My color is yellow
apple.say.apply(banana);
//My color is yellow
  所以,可以看出 call 和 apply 是为了动态改变 this 而出现的,当一个 object 没有某个方法(本栗子中banana没有say方法),但是其他的有(本栗子中apple有say方法),我们可以借助call或apply用其它对象的方法来操作。
  apply、call 的区别
  对于 apply、call 二者而言,作用完全一样,只是接受参数的方式不太一样。例如,有一个函数定义如下:
var func = function(arg1, arg2) {
  就可以通过如下方式来调用:
func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])
  其中 this 是你想指定的上下文,他可以是任何一个 JavaScript 对象(JavaScript 中一切皆对象),call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。
  JavaScript 中,某个函数的参数数量是不固定的,因此要说适用条件的话,当你的参数是明确知道数量时用 call 。
  而不确定的时候用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来遍历所有的参数。
  为了巩固加深记忆,下面列举一些常用用法:
  1、数组之间追加
var array1 = [12 , &foo& , {name &Joe&} , -2458];
var array2 = [&Doe& , 555 , 100];
Array.prototype.push.apply(array1, array2);
/* array1 值为
[12 , &foo& , {name &Joe&} , -2458 , &Doe& , 555 , 100] */
  2、获取数组中的最大值和最小值
numbers = [5, 458 , 120 , -215 ];
var maxInNumbers = Math.max.apply(Math, numbers),
maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458
  number 本身没有 max 方法,但是 Math 有,我们就可以借助 call 或者 apply 使用其方法。
  3、验证是否是数组(前提是toString()方法没有被重写过)
functionisArray(obj){
returnObject.prototype.toString.call(obj) === '[object Array]' ;
  4、类(伪)数组使用数组方法
var domNodes = Array.prototype.slice.call(document.getElementsByTagName(&*&));
  Javascript中存在一种名为伪数组的对象结构。比较特别的是&arguments 对象,还有像调用&getElementsByTagName&,&document.childNodes&之类的,它们返回NodeList对象都属于伪数组。不能应用 Array下的 push , pop 等方法。
  但是我们能通过 Array.prototype.slice.call 转换为真正的数组的带有 length 属性的对象,这样 domNodes 就可以应用 Array 下的所有方法了。
  深入理解运用apply、call
  下面就,来更深入的去理解下 apply 和 call 。
  定义一个 log 方法,让它可以代理 console.log 方法,常见的解决方法是:
function log(msg) {
console.log(msg);
  上面方法可以解决最基本的需求,但是当传入参数的个数是不确定的时候,上面的方法就失效了,这个时候就可以考虑使用 apply 或者 call,注意这里传入多少个参数是不确定的,所以使用apply是最好的,方法如下:
function log(){
console.log.apply(console, arguments);
  接下来的要求是给每一个 log 消息添加一个&(app)&的前辍,比如:
log(&hello world&);
//(app)hello world
  该怎么做比较优雅呢?这个时候需要想到arguments参数是个伪数组,通过 Array.prototype.slice.call 转化为标准数组,再使用数组方法unshift,像这样:
function log(){
var args = Array.prototype.slice.call(arguments);
args.unshift('(app)');
console.log.apply(console, args);
  说完了 apply 和 call ,再来说说bind。bind() 方法与 apply 和 call 很相似,也是可以改变函数体内 this 的指向。
  MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入&bind()方法的第一个参数作为&this,传入&bind()&方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
  直接来看看具体如何使用,在常见的单体模式中,通常我们会使用 _this , that , self 等保存 this ,这样我们可以在改变了上下文之后继续引用到它。&像这样:
var foo = {
eventBind: function(){
var _this =
$('.someClass').on('click',function(event) {
/* Act on the event */
console.log(_this.bar);
  由于 Javascript 特有的机制,上下文环境在 eventBind:function(){ } 过渡到&$('.someClass').on('click',function(event) {&}) 发生了改变,上述使用变量保存 this&这些方式都是有用的,也没有什么问题。当然使用 bind() 可以更加优雅的解决这个问题:
var foo = {
eventBind: function(){
$('.someClass').on('click',function(event) {
/* Act on the event */
console.log(this.bar);
}.bind(this));
  在上述代码里,bind() 创建了一个函数,当这个click事件绑定在被调用的时候,它的 this 关键词会被设置成被传入的值(这里指调用bind()时传入的参数)。因此,这里我们传入想要的上下文 this(其实就是 foo ),到 bind() 函数中。然后,当回调函数被执行的时候, this 便指向&foo&对象。再来一个简单的栗子:
var bar = function(){
console.log(this.x);
var foo = {
bar(); // undefined
var func = bar.bind(foo);
func(); // 3
  这里我们创建了一个新的函数 func,当使用 bind() 创建一个绑定函数之后,它被执行的时候,它的 this 会被设置成 foo , 而不是像我们调用 bar() 时的全局作用域。
  有个有趣的问题,如果连续 bind() 两次,亦或者是连续 bind() 三次那么输出的值是什么呢?像这样:
var bar = function(){
console.log(this.x);
var foo = {
var sed = {
var func = bar.bind(foo).bind(sed);
func(); //?
var fiv = {
var func = bar.bind(foo).bind(sed).bind(fiv);
func(); //?
  答案是,两次都仍将输出 3 ,而非期待中的 4 和 5 。原因是,在Javascript中,多次 bind() 是无效的。更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。
 apply、call、bind比较
  那么 apply、call、bind 三者相比较,之间又有什么异同呢?何时使用 apply、call,何时使用 bind 呢。简单的一个栗子:
var obj = {
var foo = {
getX: function() {
return this.x;
console.log(foo.getX.bind(obj)());
console.log(foo.getX.call(obj));
console.log(foo.getX.apply(obj));
  三个输出的都是81,但是注意看使用 bind() 方法的,他后面多了对括号。
  也就是说,区别是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会立即执行函数。
  再总结一下:
apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;
bind&是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。
  本文实例出现的所有代码,在。
验证消息:Admin10000
提示:常上QQ空间的朋友可关注,精彩内容不错过。
理智评论文明上网,拒绝恶意谩骂 发表评论 / 共0条评论
登录会员中心关于 js 中的 call 和 apply使用理解
您当前位置: &
[ 所属分类
在学习新的东西时候,碰到以前看过而又不理解,或则记忆不深的地方不妨回头看看书里知识点,有助于加深理解。正所谓--温故而知新。  废话不多说,直接上代码:  第一节:一个简单的例子复制代码 function add(a,b){ console.log(a+b); } function sub(a,b){ console.log(a-b); } add.call(sub,3,2); //5复制代码 总结:以上代码 定义两个方法,而最后一句话,不妨理解为 sub对象 调用了 add对象 的方法,并把参数也带入方法里。 第二节:深入理解 call 和 apply  call 和 apply的定义说明:call和apply 是函数的非继承方法,在某个特定作用范围内调用某个函数,设置函数体内this对象的值,复制代码 function NJie(){ this.name = "Njie", this.sayName = function(){ console.log(this.name); } } function KK(){ this.name ="KK"; } var n = new NJie(); var k = new KK(); n.sayName(); //NJie n.sayName.call(k); //KK复制代码  总结:比如说:k 对象没有 sayName 的函数,而 n 有这个函数,那 k 就通过call 来借 n的 sayName使用,当然也要把在 k 中的值带入到方法里。第三节:call 和 apply 的 区别  说明:call 和 apply 的区别,在于两个传入的参数的方式不一样  复制代码   // 父类 function Person(name,age){ this.name = this.age = } //子类 学生 function Student(name,age,grade){ Person.apply(this,arguments); //子类继承了父类 // Person.call(this,name,age); //当然,也可以使用 call的方法 this.grade = } //创建一个学生的实例 var s1 = new Student("倪杰","23","北京大学成人班,一年级"); console.log("您好,",s1.name,"您今年",s1.age,"岁,就读于",s1.grade,",实在太棒了");复制代码  总结:    以上的例子有两个要点:      1,是可以使用 call的方法来做 js 的继承处理;      2,call 和 apply 的区别主要是在于后面的传入参数方式不同,call传参数要把参数一一列出来,而apply则可以使用 arguments 这个属性直接带过去.  
本文前端(javascript)相关术语:javascript是什么意思 javascript下载 javascript权威指南 javascript基础教程 javascript 正则表达式 javascript设计模式 javascript高级程序设计 精通javascript javascript教程
转载请注明本文标题:本站链接:
分享请点击:
1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
既然降生到这世上,我就要好好看看它,找到属于自己的世界第一。
手机客户端
,专注代码审计及安全周边编程,转载请注明出处:http://www.codesec.net
转载文章如有侵权,请邮件 admin[at]codesec.netJS中的call、apply、bind方法的区别在JS中,this的指向是动态变化的,很可能在写程序的过程中,无意中破坏掉this的指向,所以我们需要一种可以把this的含义固定的技术,于是就有了call,apply和bind这三个方法Function.prototype.callfun.call(thisArg[, arg1[, arg2[, ...]]])可以用来指定调用call的函数的this指向(函数体的作用域),在所给定的thisArg(对象)作用域中执行该函数(call的调用者),后面的参数是函数调用过程中需要用到的数据,以逗号分隔的形式给出。代码示例function f(x,y){
console.log(x+y);
f.call(null, 1, 1)
//return 2Function.prototype.applyfun.apply(thisArg, [argsArray])apply函数与call的使用场景类似,不同的地方是在调用参数部分,直接给出的是参数数组,而不是挨个添加,这对于编码来讲,大有裨益,可以直接把参数处理成数组的形式,传递进去,省去不少功夫,也提升了自动化能力!代码示例function f(x,y){
console.log(x+y);
f.call(null, [1,1])
//return 2Function.prototype.bindfun.bind(thisArg[, arg1[, arg2[, ...]]])与上面不同的是,bind会返回一个改变this指向的新函数 ,注意这里强调的是新函数,其与之前的使用的不是同一块内存地址,所以当你需要重复使用这个函数的时候,你就不得不把其保存到一个变量,方便下次调用。上面的两个函数都是返回的执行结果,即调用即执行!此外,另外需要注意的地方是,bind函数中的首个参数,会自动成为返回新函数中参数的默认值,那么正式调用的时候,只需要给出除首个参数外,剩余参数即可。代码示例function f(x,y){
console.log(x+y);
f.call(null, [1,1])
var new_f = f.bind(null,1,1)
//return new function
//return 2需要说明的是,上面所有示例代码中的thisArg参数均用null来代替了,在未给出指定thisArg对象的情况下,null与undefined下this指向是全局对象,即js代码执行环境。-完-参考引用/1fLNrW 
 文章为作者独立观点,不代表微头条立场
的最新文章
一些值得在API设计过程中参考的Tips一些Cron任务调试的注意事项服务上线稳定运行后,需要做的第一件事儿就是确定备份周期,以防线上数据意外丢失,常用的备份方案有rsync,f指定Gem安装源的三种方式 | Ruby双拼应该是你2016年提升自己最容易成功的一个项目,也是投入产出比最高的一个项目。教你如何用Netcat在禁用SSH的服务器之间高效的传输文件(ex: 通过跳板机登陆的服务器)其实主要是推荐这款清爽的编码字体Anonymous Pro解决Rails中因require_tree导致的Assets冲突问题教你如何利用Fail2ban防止服务器被暴力破解,并使用BearyChat来做报警通知如何通过命令行指令发现是否遭到DDos攻击使用JSON Matchers最大限度的精简你的API测试代码推荐给自搭梯子翻墙的同学,使用UFW轻松搞定防火墙配置用上此利器绝对让你从此Commit时不在无话可说几个快速锁屏的小技巧教你一招快速汇率计算的小技巧介绍一款窗口管理利器Moom的使用技巧由于工作中需要用到微软家的API,所以接触到了Azure Marketplace,看了一下平台上所提供的服务告诉你Mac中常见的.DS_Store文件到底是个什么鬼能干啥介绍一种高效的终端下目录切换利器Autojump之前也写过一篇关于Rails程序部署的文章,并且也介绍到了一款部署工具Mina,不过这两者之间的差别还是蛮大继续来说昨天的Chef自动化部署的话题,昨天是理论科普篇,今天具体实践一下,并且昨天已经埋下伏笔,要举一个可之前文章中有介绍过一款Mac自带的图像处理工具Sips,用来做日常的简单图片处理需求可以说得心应手。然而在工给大家分享一个Mac中显示Finder当前打开文件完整路径的方法,类似与Windows中的地址栏,不过比地址栏更直观!本文还是接续昨天提到的《Ruby 函数式编程》,继续对里面的内容进行梳理,因为编程习惯和规范这东西说实话,真前面的文章,已经把Chef-Solo说的差不多了,不过之前的例子都用的自己定制的食谱,今天这篇来说一说Ber前面的几篇文章我们把Chef的各个部分介绍了一遍,我们知道了Chef的运作机理,也了解了一些周边的辅助工具集Markdown-Here是一款浏览器插件,其官方描述是为了解决邮件书写中快速排版格式的问题。借由Markd之前也写过一篇关于Rails程序部署的文章,并且也介绍到了一款部署工具Mina,不过这两者之间的差别还是蛮大继续来说昨天的Chef自动化部署的话题,昨天是理论科普篇,今天具体实践一下,并且昨天已经埋下伏笔,要举一个可前面两篇一篇用来说基本概念,一篇用来实战Chef-Solo,这篇就来说说Knife-Solo这个命令行工具。本文还是接续昨天提到的《Ruby 函数式编程》,继续对里面的内容进行梳理,因为编程习惯和规范这东西说实话,真之前文章中有介绍过一款Mac自带的图像处理工具Sips,用来做日常的简单图片处理需求可以说得心应手。然而在工Ruby程序设计中要用到大量的Blocks(语法块),最典型的当属each方法中的语法块,在Ruby中其实际搞网络编程的同学,应该对这几个概念都不会陌生,当然Javascript Guy也应该对他们很熟悉,因为毕竟JConsole功能是我喜欢Rails的一大原因,因为其加载了Rails环境(上下文)的irb,所以能很直观的不知道你有没有遇到过下面几种情况:一个新的feature开发完成了,要进行一个Commit,但Commit结Git: 如何优雅的进行「git pull」操作之前的文章有介绍过git pull的完整含义,但为了引出今天介绍Mac OS X 上的常用快捷键,千真万确是「常用」!Rails 4.2以后Active Job成了内置的异步任务处理模块。之前处理异步任务方案有Resque,SRails: pluck与select的区别对于程序而言,日志的重要性就不必再强调了吧,它能帮你勘探你每个到不了的地方,比如Runtime环境,亦或者D在*nix系统下工作久了,慢慢的会积累出一大堆的rc配置文件,并且这些rc配置出来的环境会让使用它们成为你的在Github上看到一个「SQL Joins Visualizer」的项目,作者把表示Join关系的韦恩图变本文主要介绍Siege,因为Siege是ab、Http_load、Webbench、Sie四者中,在Mac上安装和使用最便利的。Ajax跨域问题的两种解决方案: JSONP与CORS在Git中每次Commit都可以被算作是一个版本,我们经常按照功能和模块来划分Commit,但并不是所有的功RESTful API 状态码确定的正确姿势rigongyizu365日拱一卒热门文章最新文章rigongyizu365日拱一卒js中Function的apply方法与call方法理解
调试的时候走的是标红的这段代码,然后用到了callback.call这个函数,于是翻看了一下《js高级程序设计》,其中有比较深的解释。
首先,function是一个指向Function对象,函数名是一个指向函数的指针。那么在函数体内,就会有一个作用域,即this关键字。
this关键字指的是函数运行的作用域,举个例子来说,
&script type=&text/javascript&&
& & & & function funcA() {
& & & & & & alert(this);
& & & & & & alert(&Function A&);
上面这段代码中的函数funcA定义在全局环境中,那么函数体内的this即window对象。
下面该到call和apply的说明了。以call函数为例,call的第一个参数,就是改变函数的作用域,后面的参数为传入函数的所需的参数,必须与原函数的参数一直,举例说明:
&script type=&text/javascript&&
& & & & var testO = { name: &Lily& };
& & & & function funcA(a,b) {
& & & & & & alert(this);
& & & & & & alert(&Function A&);
& & & & function funcB(a, b) {
& & & & & & funcA.call(testO, a, b);
& & & & funcB(1,2); &//this变成了testO
& & &/script&
我们定义funcB函数的中,调用了funcA的call函数,这个时候我们改变了funcA中this的指向,原本指向window的,现在指向了call的第一个参数testO这个对象。而且调用call时,因为funcA函数有两个参数,所以如果要想funcA传递参数,必须一一指出参数,即后面的两个参数a和b,或者可以只穿第一个参数
即:funcA.call(testO);或者只传a,即:funcA.call(testO,a);
而apply与call的区别仅在于,apply的第二个参数可以是数组形式,而且不必一一指出参数,funcA.apply(testO,[a,b])
介绍完call与apply的基本用法,该说说他哥俩真正的用武之地了,扩充函数赖以运行的作用域。
&script type=&text/javascript&&
& & & & window.color = &透明&;
& & & & var testObj = { color: &红色& };
& & & & function testFuc() {
& & & & & & alert(this.color);
& & & & $(function () {
& & & & & & 1.testFuc(); //弹出&透明&
& & & & & & 2.testFuc(this); //弹出&undefined&
& & & & & & 3.testFuc.call(this.parent); //弹出&透明&
& & & & & & 4.testFuc.call(window); //弹出&透明&
& & & & & & 5.testFuc.call(testObj); //弹出&红色&
& & & & });
上面这段代码演示了call的作用。第一个函数调用,this指向了window,所以弹出了window的color属性。
第二个函数可能有些朋友以为也会弹出透明,但是请先确定我们的函数运行在$(function(){});中,这个jQuery的函数,了解jQuery的朋友都很清楚,在
$(function(){});中this的作用域指向的是document,然后我们调用testFunc,要弹出document的color,当然是未定义的。
第三个函数将testFunc的this指向了document的亲爹window,弹出window的color当然也是没有问题的。
第四个函数就更加直白了,把window传进去了
第五个函数,将testFunc的this指向了testObj,弹出了红色。
讲到这里,用法大家应该都有所了解了,但是具体怎么去理解怎么去使用还是看自己的套路。
我是这么理解的,可以把这种用法看成是C#或者java中的泛型方法。比如一个C#方法的定义
public void Test&T&(T a, T b) { }
这样我们就可以实现对方法的扩展,实现通用的目的。}

我要回帖

更多关于 call和apply 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信