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. SharePoint 2013异常信息的查看

    刚刚学习SharePoint开发的时候,经常遇到一些异常,却不能直接看到详细信息,很郁闷.这里做下简单的整理,方便查找: 1.代码未处理异常出现黄页——”‘/’应用程序中的服务器错误.运行时错误“. ...

  2. 换行(\r)和回车(\n)

    主要摘录自2篇blog: http://www.cnblogs.com/clarkchen/archive/2011/06/02/2068609.html http://www.360doc.com/ ...

  3. [fortify] 变量覆盖漏洞

    一.全局变量覆盖当register_global=ON时,变量来源可能是各个不同的地方,比如页面的表单,Cookie等. <?php echo "Register_globals: & ...

  4. Spring中使用Schedule调度

    在spring中两种办法使用调度,以下使用是在spring4.0中. 一.基于application配置文件,配置入下: <bean id="jobDetail" class ...

  5. EXCEL设置选中单元格样式

    你想这样啊,试试这段代码看行不:右键工作表名称--查看代码,在空白处粘贴就可以 Private Sub Worksheet_SelectionChange(ByVal Target As Range) ...

  6. MongoDB初步(一)

    1.软件下载:mongodb-win32-x86_64-2008plus-ssl-3.4.1-signed.msi 2.下载补丁:hotfix kb2731284

  7. ORA-12705问题解决过程

    最近开发C#加ORACLE的程序,就有一台电脑连接的时候报错误 ORA-12705: Cannot access NLS data files or invalid environment speci ...

  8. SQL 常用语句

    替换表中某个字段中的某些字符:(将ConfigValue列中的A值替换为B) update SysConfigParams set ConfigValue=replace(ConfigValue,'A ...

  9. (转载)JAVA敏捷开发环境搭建

    整个软件项目分为四个环境 开发本地环境.开发环境.测试环境.IDC环境.和传统C++开发不一样的模式是多了第一个开发本地环境.这是为什么呢,因为目前大部分开发人员还是比较熟悉windows下开发.对于 ...

  10. Visual Studio 2013 错误提示“未找到与约束匹配”的修正

    昨天由于项目需要,在开发电脑上安装了Microsoft Office Project 2007来做时间计划,但是安装之后第二天重新打开VS之后,就无法打开项目或者原有程序文件无法打开.错图提示界面如下 ...