apply()方法定义

函数的apply()方法和call方法作用相同,区别在于接收的参数的方式不同。
apply()方法接收两个参数,一个是对象,一个是参数数组。

apply()作用

1、用于延长函数的作用域

示例:

  1. var color='red';
  2. var o={color:'blue'};
  3. function sayColor(){
  4. console.log(this.color);
  5. }
  6. sayColor();//"red"
  7. sayColor.apply(o);//"blue"

这里通过apply()方法把函数动态绑定到了对象o上了,这时this指向o对象,得到结果"blue"。

2、对象不需要与方法有任何耦合关系

下面举个耦合的例子,看如何通过apply来解决这种耦合。

  1. var color='red';
  2. var o={color:'blue'};
  3. function sayColor(){
  4. console.log(this.color);
  5. }
  6. o.sayColor=sayColor;
  7. o.sayColor();//"blue"

这里先将函数放到了对象o中,这里对象和方法就紧耦合到一起了,方法的调用必须通过对象o。

没有使用apply()和call()方法那样灵活。
重构上面代码,得到前例中的代码。

  1. var color='red';
  2. var o={color:'blue'};
  3. function sayColor(){
  4. console.log(this.color);
  5. }
  6. sayColor();//"red"
  7. sayColor.apply(o);//"blue"

这里对象并没有绑定任何方法,只是在需要使用的时候,利用函数的apply或call方法来动态绑定。

对象和方法之间没有耦合在一起。这里还可以通过ES5提供的bind()方法来完成

3、实现可变参数函数传参

下面一个计算任意数量数字平均值的函数

  1. average(1,2,3);
  2. average(1);
  3. average(3,1,2,3,5,6,7,8,9);
  4. average(1,2,3,5,2,1,5,6,1,10);

average函数是一个称为可变参数或可变元函数(函数的元数是指其期望的参数个数)的例子。

当然这个函数也可以写成一个接收数组的形式。

  1. averageOfArray([1,2,3]);
  2. averageOfArray([1]);
  3. averageOfArray([3,1,2,3,5,6,7,8,9]);
  4. averageOfArray([1,2,3,5,2,1,5,6,1,10]);

使用可变参数的函数更简洁、优雅。可变参数函数具有便捷的语法,至少让调用者预先明确地知道提供了多少个参数。

如果我有这样一个数组

  1. var scores=getAllScores();

如何使用average函数计算平均值呢?

1.可变参数函数版本。
这时就可以和apply()方法配合使用,这里因为函数并没用引用this变量,因此第一个参数我们传入一个null。代码如下:

  1. var scores=getAllScores();
  2. average.apply(null,scores);

2.直接参数为数组的形式

这里可以直接传入数组参数。

  1. var scores=getAllScores();
  2. averageOfArray(scores);

以上两种形式,个人觉得都是可以,反而第二种更简单。多知道一种方法,对于遇到别人写的函数时,可以轻松应对,不需要重构代码。这个好处反而更多。

4、实现可变参数方法的传值

示例:buffer对象包含一个可变参数的append方法,该方法添加元素到函数内部的state数组中。

  1. var buffer={
  2. state:[],
  3. append:function(){
  4. for(var i=0,n=arguments.length;i<n;i++){
  5. this.state.push(arguments[i]);
  6. }
  7. }
  8. };

这时append方法可以接受任意多个参数。

  1. buffer.append('Hello,');
  2. buffer.append('firtName',' ','lastName','!');
  3. buffer.append('newLine');

形式如

  1. buffer.append(arg1,arg2,arg3,...)

借助apply方法的this参数,我们可以指定一个可计算的数组调用append方法

  1. buffer.append.apply(buffer,getInputStrings());

注意:这里的buffer很重要,如果传递不同的对象,则append方法将尝试修改该错误对象的state属性。

提示

  • 使用apply方法指定一个可计算的参数数组来调用可变参数的函数
  • 使用apply方法的第一个参数给可变参数的方法提供一个接收者

附录一

average函数

  1. function average(){
  2. var args=[].slice.call(arguments);
  3. var sum=args.reduce(function(prev,cur){
  4. return prev+cur;
  5. });
  6. return parseInt(sum/args.length,10);
  7. }

averageOfArray函数

  1. function averageOfArray(arr){
  2. var sum=arr.reduce(function(prev,cur){
  3. return prev+cur;
  4. });
  5. return parseInt(sum/arr.length,10);
  6. }

ES5 bind()方法

这个方法创建一个函数的实例,其this值会被绑定到传给bind()函数的值。
例如
  1. var color='red';
  2. var o={color:'blue'};
  3. function sayColor(){
  4. console.log(this.color);
  5. }
  6. var oSayColor=sayColor.bind(o);
  7. oSayColor();//"blue"

兼容低版本,参考使用下面的版本

  1. if (!Function.prototype.bind) {
  2. Function.prototype.bind = function(oThis) {
  3. if (typeof this !== 'function') {
  4. // closest thing possible to the ECMAScript 5
  5. // internal IsCallable function
  6. throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
  7. }
  8.  
  9. var aArgs = [].slice.call(arguments, 1),
  10. fToBind = this,
  11. fNOP = function() {},
  12. fBound = function() {
  13. return fToBind.apply(this instanceof fNOP? this: oThis,
  14. aArgs.concat(Array.prototype.slice.call(arguments)));
  15. };
  16.  
  17. if (this.prototype) {
  18. // Function.prototype doesn't have a prototype property
  19. fNOP.prototype = this.prototype;
  20. }
  21. fBound.prototype = new fNOP();
  22.  
  23. return fBound;
  24. };
  25. }

  

[Effective JavaScript 笔记]第21条:使用apply方法通过不同数量的参数调用函数的更多相关文章

  1. [Effective JavaScript 笔记]第50条:迭代方法优于循环

    "懒"程序员才是好程序员.复制和粘贴样板代码,一但代码有错误,或代码功能修改,那么程序在修改的时候,程序员需要找到所有相同功能的代码一处处进行修改.这会使人重复发明轮子,而且在别人 ...

  2. [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

    js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...

  3. [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

    js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...

  4. [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符

    “1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...

  5. [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

    函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...

  6. [Effective JavaScript 笔记]第23条:永远不要修改arguments对象

    arguments对象并不是标准的Array类型的实例.arguments对象不能直接调用Array方法. arguments对象的救星call方法 使得arguments可以品尝到数组方法的美味,知 ...

  7. [Effective JavaScript 笔记]第22条:使用arguments创建可变参数的函数

    第21条讲述使用可变参数的函数average.该函数可处理任意数量的参数并返回这些参数的平均值. 如何创建可变参数的函数 1.实现固定元数的函数 书上的版本 function averageOfArr ...

  8. [Effective JavaScript 笔记]第20条:使用call方法自定义接收者来调用方法

    不好的实践 函数或方法的接收者(即绑定到特殊关键字this的值)是由调用者的语法决定的.方法调用语法将方法被查找的对象绑定到this变量,(可参阅之前文章<理解函数调用.方法调用及构造函数调用之 ...

  9. [Effective JavaScript 笔记]第33条:使构造函数与new操作符无关

    当使用函数作为一个构造函数时,程序依赖于调用者是否记得使用new操作符来调用该构造函数.注意:该函数假设接收者是一个全新的对象. 一个例子 function User(name,pwd){ this. ...

随机推荐

  1. java heep space错误解决办法

    1.双击tomcat 2.Open launch configuration 3.Argument 4. VM arguments中添加:-Xmx1024M -Xms512M -XX:MaxPermS ...

  2. JavaScript中的各种小坑汇总

    1.Number()将部分非数字类型转换为0 强制转换为数值类型函数: parseFloat.parseInt 优点:对非数值类型统一返回NaN 缺点:会将一部分符合数值类型的字符串也识别为数值 pa ...

  3. 【转载】gcc 使用中常用的参数及命令

    本文转载自:http://www.cnblogs.com/yaozhongxiao/archive/2012/03/16/2400473.html 如需转载,请注明原始出处.谢谢. --------- ...

  4. onload是代码在也买你的追加元素的完成,而不是http请求的完成

  5. get与post

    1. get是从服务器上获取数据,post是向服务器传送数据.2. get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到.post是通过H ...

  6. KMP和扩展KMP

    文章网上太多这里提一下代码细节: KMP: scanf("%s\n",s); scanf("%s\n",t); int ls=strlen(s),lt=strl ...

  7. php empty()和isset()的区别

    在使用 php 编写页面程序时,我经常使用变量处理函数判断 php 页面尾部参数的某个变量值是否为空,开始的时候我习惯了使用 empty() 函数,却发现了一些问题,因此改用 isset() 函数,问 ...

  8. hdu3986 spfa+枚举

    这题让我第一次感受到了什么叫做在绝望中A题.这题我总共交了18次,TLE不知道几次,WA也不知道几次. 这题不能用dijkstra,用这个我一直超时(我没试过dij+优先队列优化,好像优先队列优化后可 ...

  9. 基于spring mvc的注解DEMO完整例子

    弃用了struts,用spring mvc框架做了几个项目,感觉都不错,而且使用了注解方式,可以省掉一大堆配置文件.本文主要介绍使用注解方式配置的spring mvc,之前写的spring3.0 mv ...

  10. 『jQuery』.html(),.text()和.val()的概述及使用

    转自http://www.jb51.net/article/35867.htm 如何使用jQuery中的.html(),.text()和.val()三种方法,用于读取,修改元素的html结构,元素的文 ...