call及apply在js里经常碰得到,但一直感觉很陌生,不能熟练使用。怎样才能熟练应用呢?

为什么存在call和apply?

在javascript OOP中,我们经常会这样定义:

function cat(){

}

cat.prototype={
food:"fish",
say: function(){
alert("I love "+this.food);
}
} var blackCat = new cat;
blackCat.say();

但是如果我们有一个对象whiteDog = {food:"bone"},我们不想对它重新定义say方法,那么我们可以通过callapplyblackCatsay方法:

blackCat.say.call(whiteDog);//可以理解为whiteDog"继承"了blackCat的say方法

所以,可以看出call和apply是为了动态改变this而出现的,当一个object没有某个方法,但是其他的有,我们可以借助call或apply用其它对象的方法来操作。

用的比较多的,通过document.getElementsByTagName选择的dom 节点是一种类似array的array。它不能应用Array下的push,pop等方法。我们可以通过:

var domNodes =  Array.prototype.slice.call(document.getElementsByTagName("*"));

这样domNodes就可以应用Array下的所有方法了。

call和apply的区别

call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的。换句话说,就是为了改变函数体内部 this 的指向。

因为 JavaScript 的函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。二者的作用完全一样,只是接受参数的方式不太一样。

例如,有一个函数 func1 定义如下:

var func1 = function(arg1, arg2) {};

就可以通过 func1.call(this, arg1, arg2); 或者 func1.apply(this, [arg1, arg2]); 来调用。其中 this 是你想指定的上下文,他可以任何一个 JavaScript 对象(JavaScript 中一切皆对象),call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。

JavaScript 中,某个函数的参数数量是不固定的,因此要说适用条件的话,当你的参数是明确知道数量时,用 call,而不确定的时候,用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来便利所有的参数。

深入探讨

Function.prototype.call()
Function.prototype.apply()

方法定义

**call方法: **

语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]])

定义:调用一个对象的一个方法,以另一个对象替换当前对象。

说明:

call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。

如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。

apply方法:

语法:apply([thisObj[,argArray]])

定义:应用某一对象的一个方法,用另一个对象替换当前对象。

说明:

如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。

如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。

常用实例

a、

function add(a,b)
{
alert(a+b);
}
function sub(a,b)
{
alert(a-b);
} add.call(sub,3,1);

这个例子中的意思就是用 add 来替换 sub,add.call(sub,3,1) == add(3,1) ,所以运行结果为:alert(4); // 注意:js 中的函数其实是对象,函数名是对 Function 对象的引用。

b、

function Animal(){
this.name = "Animal";
this.showName = function(){
alert(this.name);
}
} function Cat(){
this.name = "Cat";
} var animal = new Animal();
var cat = new Cat(); //通过call或apply方法,将原本属于Animal对象的showName()方法交给对象cat来使用了。
//输入结果为"Cat"
animal.showName.call(cat,",");
//animal.showName.apply(cat,[]);

call 的意思是把 animal 的方法放到cat上执行,原来cat是没有showName() 方法,现在是把animal 的showName()方法放到 cat上来执行,所以this.name 应该是 Cat

c、实现继承

function Animal(name){
this.name = name;
this.showName = function(){
alert(this.name);
}
} function Cat(name){
Animal.call(this, name);
} var cat = new Cat("Black Cat");
cat.showName();

Animal.call(this) 的意思就是使用 Animal对象代替this对象,那么 Cat中不就有Animal的所有属性和方法了吗,Cat对象就能够直接调用Animal的方法以及属性了.

d、多重继承

function Class10()
{
this.showSub = function(a,b)
{
alert(a-b);
}
} function Class11()
{
this.showAdd = function(a,b)
{
alert(a+b);
}
} function Class2()
{
Class10.call(this);
Class11.call(this);
}

很简单,使用两个 call 就实现多重继承了

推荐阅读

1、Function.prototype.apply() - JavaScript | MDN

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

2、面向对象编程概述 -- JavaScript 标准参考教程(alpha)

http://javascript.ruanyifeng.com/oop/basic.html#toc10

3、JS中的call()和apply()方法 - 每天进步一点点! - ITeye技术网站

http://uule.iteye.com/blog/1158829

引用:

1、https://www.zhihu.com/question/20289071/answer/14644278

2、http://uule.iteye.com/blog/1158829

js笔记——理解js中的call及apply的更多相关文章

  1. 秒味课堂Angular js笔记------Angular js中的工具方法

    Angular js中的工具方法 angular.isArray angular.isDate angular.isDefined angular.isUndefined angular.isFunc ...

  2. [JS]如何理解JS中的类和对象

    -------------------------------------------------------------------------------------------- 变量:自由的 ...

  3. 理解JavaScript中的call和apply方法

    call方法 总的来说call()有这几种作用:1.可以借用另一个对象的方法.2.改变this的指向(重要).3.将arguments数组化.下面详细介绍这三种作用: 1.可以借用另一个对象的方法:当 ...

  4. 简单理解Javascript中的call 和 apply

    javascript中面向对像的能力是后来加进来的, 为了兼容性, 所以整出了很多奇特的东西, function Animal(){ this.name = "Animal"; t ...

  5. 【学习笔记】六:面向对象的程序设计——理解JS中的对象属性、创建对象、JS中的继承

    ES中没有类的概念,这也使其对象和其他语言中的对象有所不同,ES中定义对象为:“无序属性的集合,其属性包含基本值.对象或者函数”.现在常用的创建单个对象的方法为对象字面量形式.在常见多个对象时,使用工 ...

  6. 【学习笔记】彻底理解JS中的this

    首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然 ...

  7. 【学习笔记】深入理解js原型和闭包系列学习笔记——精华

    深入理解js原型和闭包笔记: 1.“一切皆是对象”,对象是属性的集合. 丨 函数也是对象,但是使用typeof时为什么函数返回function而 丨  不是object呢,js为何要对函数做这样的区分 ...

  8. 【学习笔记】深入理解js原型和闭包(0)——目录

    文章转载:https://www.cnblogs.com/wangfupeng1988/p/4001284.html 说明: 本篇文章一共16篇章,外加两篇后补的和一篇自己后来添加的学习笔记,一共19 ...

  9. 怎么理解js中的事件委托

    怎么理解js中的事件委托 时间 2015-01-15 00:59:59  SegmentFault 原文  http://segmentfault.com/blog/sunchengli/119000 ...

随机推荐

  1. Kinect2 随记

    2016.03.30 calibration工作: 地板砖1.24m一格,大概走到2.5m时5*7的pattern开始无法检测到. 20种板上位姿*20种黑板位姿=400幅图像. 距离越远,水平角能检 ...

  2. shell中括号的使用

    在这里我想说的是几种shell里的小括号,大括号结构和有括号的变量,命令的用法,如下: 1.${var} 2.$(cmd) 3.()和{} 4.${var:-string},${var:+string ...

  3. 【线段树套平衡树】【pb_ds】bzoj3196 Tyvj 1730 二逼平衡树

    线段树套pb_ds里的平衡树,在洛谷OJ上测试,后三个测试点TLE #include<cstdio> #include<algorithm> #include<ext/p ...

  4. unity3d多线程坑

    单独起了一个线程来处理网络相关操作,比较常规的做法.本身没啥特别的东西,碰到了一个不大不小的坑折腾了好久,记录下来吧. 简单的说就是子线程中抛出的异常,如果没有catch的话,会导致子线程悄无声息的退 ...

  5. C# 图片压缩

    /// <summary>        /// 图片压缩方法        /// </summary>        /// <param name="sF ...

  6. 经典排序算法(PHP)

    1.冒泡算法,排序算法,由于在排序过程中总是小数往前放,大数往后放,相当于气泡往上升,所以称作冒泡排序 function maopao_fun($array){ $count = count($arr ...

  7. zoj 3725 - Painting Storages(动归)

    题目要求找到至少存在m个连续被染成红色的情况,相对应的,我们求至多有m-1个连续的被染成红色的情况数目,然后用总的数目将其减去是更容易的做法. 用dp来找满足条件的情况数目,, 状态:dp[i][0] ...

  8. Ubuntu16.04使用阿里云镜像安装Mongodb

    一.概述 近日要在新的Ubuntu16.04系统上安装MongoDB,某度结果后直接从Mongo官网直接获得3.2版本的下载链接,结果在下载时发觉速度慢的可怜.迫于无奈,只能找国内的镜像下载.切换国内 ...

  9. 《与mysql零距离接触》视屏学习笔记

    1.数据表的增删改查操作(crud): 对于表: 增:create  table  XXXX 删:drop table XXXX 改:alter table XXXX rename to XXXX 查 ...

  10. C#操作内存读写方法的主要实现代码

    C#操作内存读写方法是什么呢?让我们来看看具体的实例实现: using System.Runtime.InteropServices; using System.Text; publicclass F ...