简介:apply()和call()都是属于Function.prototype的一个方法属性,它是JavaScript引擎内在实现的方法,因为属于Function.prototype,所以每个Function实例,也就是每个方法都能使用apply和call方法。

作用:call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向。因为 JavaScript 的函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。(需要理解JavaScript的执行环境和作用域的概念)

介绍完这两个方法后,说下它们的异同点:

相同点:这两个方法都是劫持另外一个对象的方法,继承另外一个对象的属性. 怎样理解这句话呢?代码如下:

例子 一:

    function people(){
/*this.name="无名氏";*/
this.sayName=function(){
alert("您的姓名是:"+this.name);
}
}
function xiaohua(){
this.name="小花";
people.call(this); //这里使用call()方法的作用是,当前this对象(xiaohua对象),劫持了people对象,所以people中的this指向了xiaohua对象,所以xiaohua对象拥有了
//所有people对象的方法和属性
}
var aa=new xiaohua();
aa.sayName(); //输出: 您的姓名是:小花

例子二:

function cat() {
}
cat.prototype={
food:"fish",
say:function(){
alert("I love "+this.food)
}
}
var blackcat=new cat();
blackcat.say(); //输出:I love fish
这里做个假设我们有一个对象whiteDog={food:"bone"},我不想对它重新定义say方法,因为这个say方法对需求来说完全适用!这个使用就需要使用call方法了!代码如下:
function cat() {
}
cat.prototype={
food:"fish",
say:function(){
alert("I love "+this.food)
}
}
var blackcat=new cat();
//这里做个假设我们有一个对象whiteDog={food:"bone"},我不想对它重新定义say方法,因为这个say方法对需求来说完全适用
var whiteDog={food:"bone"};
blackcat.say.call(whiteDog); //这句代码的意思是blackcat对象实例里面的say方法属性里面的this指向whiteDog对象,所以say方法里面的food属性就被whiteDog里面的food属性替换掉了
whiteDog.say();//输出I love bone

例子三:

下面这个例子据说是网易的前端面试题,来look,look

    var testA = function (b) {
return this.a + b;
};
var obj = {a: 2};
var testB = testA.myBind(obj, 1);
alert(testB);

问题是:怎样实现myBind()方法,才能使testB的值3;

先一步步分析,

(1)我们发现myBind()方法是通过testA()方法调用的,我们知道在JavaScript中所有的方法都是一个对象,而所有的方法都继承自Function对象,所以所有在Function.prototype的方法和属性,将被所有的方法实例共享,比如call,apply。所有的方法实例都能通过fun1.(Function.prototype的中定义方法和属性)的形式调用。

而这里的myBind也是通过方法实例调用的方法,这种情况只有两种可能:

1:是上面所分析的是Function.prototype的方法实例,被所有的方法所共享的方法

2:内嵌函数,嵌套在testA函数中的函数

但是分析testA方法的形参和返回值,排除了第二种可能,那只能是第一种情况,代码如下:

    Function.prototype.myBind=function(object,extra){  //当哪个方法调用myBind方法,其this指针就指向该方法
return this.call(object,extra); //传入的object对象劫持了testA对象,所以testA对象中的this指向objetc对象
}
var testA = function (b) {
return this.a + b;//这里的this指向object对象,所以this.a=2,b=1;
};
var obj = {a: 2};
var testB = testA.myBind(obj, 1);
alert(testB);//输出:3

例子四:

通过document.getElementsByTagName选择的dom 节点是一种类似array的array。它不能应用Array下的push,pop等方法。我们可以通过:
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
这样domNodes就可以应用Array下的所有方法了。
 
不同点:apply()和call()方法的区别就是在劫持对象后传递的参数类型不同,apply可以传递一个数组,而call只能一个参数一个参数传
 
 
例子五:个人觉得是网上理解call方法比较好的一种解释,也是比较好记的一种解释,下面看代码:
<script>
function add(para1,para2) {
alert(this); //输出:function substract(para1,para2) {return para1-para2;}
return para1+para2;
}
function substract(para1,para2) {
return para1-para2;
}
alert(window.add.call(window.substract,1,2));//输出:3
// 这里注意:这里的上下文只和属性和方法有关,也就是说add方法劫持了substract方法的上下文对象,能使用其内部的属性和方法
//但是其return语句并不会被覆盖,还是输出return para1+para2 //首先先分析下上面这段语句的执行过程,首先将add的上下文对象替换成substract方法的对象,
// 然后调用add方法并传入1和2两个参数 </script>

例子六:使用Call()方法实现单继承

<script>
function Animal(name) {
/* console.log(this);//输出Cat对象*/
this.name=name;
this.sayName=function () {
alert(this.name);
}
}
function Cat(name) {
Animal.call(this,name);
//首先Animal劫持了this(Cat)对象,将Animal中的上下文替换成了Cat的上下文,更具上面的输出可以看出,然后调用Animal方法并传入
//name参数给Aniaml方法,我个人觉得应该是js引擎在做完上面的操作后返回一个Animal和Cat的结合的实体引用回去
//所以我改变上面的代码加了一个 return,发现没有影响,也印证了我的猜测
}
var cat=new Cat("cat");
cat.sayName();//输出:cat,根据输出得知,call方法可以实现oop的继承功能
</script>

例子七:使用call实现多继承,上面的单继承如果理解了的话,那么多继承也就很简单了

<script>
function Add()
{
this.a=1;
this.b=2;
this.add=function(a,b)
{
return a+b;
}
}
function Substract()
{
this.sub=function(a,b)
{
return a-b;
}
}
function Operation(a,b)
{
Add.call(this,a,b);
Substract.call(this,a,b);
}
var op=new Operation();
alert(op.add(1,2));//输出:3
alert(op.sub(1,2));//输出:-1 //终极版分析:
//分析上面方法的执行过程,首先初始化Operation对象,然后Add劫持Operation,Add内部的this指向Operation
//其实这个劫持过程可以理解为在初始化Operation对象的时候,将Add对象初始化为自己的内部属性,方便调用
//这个分析我是更具在chrome中的js运行过程看出来的,纯属我个人的观点
</script>

JavaScript之call()和apply()方法详解的更多相关文章

  1. Js apply 方法 详解

    Js apply方法详解 我在一开始看到JavaScript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...

  2. angularJS中$apply()方法详解

    这篇文章主要介绍了angularJS中$apply()方法详解,需要的朋友可以参考下   对于一个在前端属于纯新手的我来说,Javascript都还是一知半解,要想直接上手angular JS,遇到的 ...

  3. Js apply方法详解,及其apply()方法的妙用

    Js apply方法详解 我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...

  4. 深入学习JavaScript: apply 方法 详解(转)——非常好

    主要我是要解决一下几个问题: 1.        apply和call的区别在哪里 2.        什么情况下用apply,什么情况下用call 3.        apply的其他巧妙用法(一般 ...

  5. JavaScript: apply 方法 详解(转)——非常好

    转载自  http://www.cnblogs.com/KeenLeung/archive/2012/11/19/2778229.html 我在一开始看到javascript的函数apply和call ...

  6. 深入学习JavaScript: apply 方法 详解

    我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这里我做如下笔记,希望和大家 ...

  7. angularjs $scope.$apply 方法详解

    myApp.controller('firstController',function($scope,$interval){ $scope.date = new Date(); setInterval ...

  8. Js apply方法详解

    我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这里我做如下笔记,希望和大家 ...

  9. JavaScript原生对象属性和方法详解——Array对象

    http://www.feeldesignstudio.com/2013/09/native-javascript-object-properties-and-methods-array/ lengt ...

随机推荐

  1. 利用netstat和tasklist查看PC的端口占用情况

    经常,我们在启动应用的时候发现系统需要的端口被别的程序占用,如何知道谁占有了我们需要的端口? 1.Windows平台在windows命令行窗口下执行: E:\oracle\ora92\bin>n ...

  2. 【Lucene】挖掘相关搜索词

    搜索引擎中往往有一个可选的搜索词的列表,当搜索结果太少时,可以帮助用户扩展搜索内容,或者搜索结果太多的时候可以帮助用户深入定向搜索.一种方法是从搜索日志中挖掘字面相似的词作为相关搜索词列表.另一种方法 ...

  3. C++流操作之fstream

    在Windows平台对文件进行存取操作可选的方案有很多,如果采用纯C,则需要用到File*等,当然也可以直接调用Windows API来做:如果采用C++,首先想到的就是文件流fstream.虽然在C ...

  4. POJ——多项式的加法

    1:多项式加法 查看 提交 统计 提问 总时间限制:  1000ms  内存限制:  5000kB 描述 我们经常遇到两多项式相加的情况,在这里,我们就需要用程序来模拟实现把两个多项式相加到一起.首先 ...

  5. 【Daily】 2014-4-28

    KEEP GOING  表达产品想法, 探讨产品问题, 倾听可能性问题. 一次就做好, 有成果展示, 主动展示 先确立图, 后确立代码. Hold dream, and never let it go ...

  6. Hibernate 配置详解(9)

    hibernate.cache.use_structured_entries Hibernate文档上介绍,该属性是用于把对象以一种更易读的方式放到二级缓存中,这样,在对二级缓存进行监控的时候就更容易 ...

  7. c++编程中的后缀

    .a 静态库 (archive) .C.c.cc.cp.cpp.cxx.c++ C++源代码(需要编译预处理) .h C或者C++源代码头文件 .ii C++源代码(不需编译预处理) .o 对象文件 ...

  8. php上传图片到server

    php文件上传中会用到$_FILES系统函数 一.$_FILES系统函数 PHP编程语言中的常见的$_FILES系统函数使用方法有: $_FILES['myFile']['name'] 显示clien ...

  9. 说说数据库架构,ORM缓存和路由

    为什么在ORM层做缓存,而不是DB层 ORM能有效地提高程序员的开发效率,程序员更喜欢操作对象而不是数据库,他们不关心也不想手写一堆SQL语句,毕竟一个公司里普通程序员要占多数,他们并不是非常熟悉数据 ...

  10. SQL SERVER2012 无法连接远程服务器

    SQL SERVER2012 无法连接远程服务器,报"尝试读取受保护的内存"错误. 解决方法: 运行CMD,输入 netsh winsock reset,回车.重启SSMS,搞定.