call,apply,bind
| 一、call&apply |
call, apply都属于Function.prototype的方法,因为属于Function.prototype,所以每个Function对象实例,也就是每个方法都有call, apply属性啦。
如果不明白,请见“Javascript之一切皆为对象3”。
而且它们的作用都是一样的,只是使用方式不同而已。
作用:借用别人的方法来调用,就像自己有这个方法一样。
咦,那它们怎样才能达到这目的呢?
对象。
对象?
是的,其实就是改变执行上下文对象的内部指针,因为在Javascript中,代码总有一个执行上下文对象,那么当我手动改变它时,就可以改变这个执行上下文啦,也就可以利用非自己的方法成为自己的方法哦。
我们一起来写个Demo。
假如,我有一个方法a,它的作用是输出对象的名字this.name;那么当我使用call或者apply改变它的执行上下文对象时,它的输出结果是不一样的。
什么意思?
详情请见下代码:
<!DOCTYPE html>
<head>
<title>call&apply</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<script>
var name = 'windowName';
//方法a的作用,是输出对象的名字
function a(){
console.log(this.name);
}
function b(){
this.name = 'bName';
}
//将a方法的执行上下文对象指向window
a.call(window);
//将a方法的执行上下文对象指向new b()
a.call(new b());
</script>
</body>
</html>
执行上述代码,结果如下:

看见了么?所以说call,apply的作用就是借用别人的方法,改变别人方法的执行上下文对象为自己,成为自己的方法,为己所用。
注意: call或apply的第一个参数传的是什么,它们就会将其默认为执行上下文对象。倘若我们没有指明call或apply的执行上下文对象,即,call和apply的第一个参数是null、undefined或为空时,在非严格模式下,函数内的this指向window或global,浏览器就是window。严格模式下,null为null,undefined或空为undefined。
什么意思,请见下面的demo(仅以call举例且为非严格模式):
<!DOCTYPE html>
<head>
<title>call&apply</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<script>
function print(){
console.log(this);
};
//将第一个参数数字1,作为执行上下文对象
print.call(0,1,2);
//将第一个参数字符串'123',作为执行上下文对象
print.call('123');
//将第一个参数true,作为第执行上下文对象
print.call(true);
//将第一个参数对象,作为执行上下文对象
print.call(new Object());
//将null传入
print.call(null);
//将undefined传入
print.call(undefined);
//不传任何参数
print.call();
</script>
</body>
</html>
看见了么,我上面传入的依次是数字,字符串,true,对象,null,undefined和空,得到下面的结果:

那么,call与apply既然作用一样,那它们有什么区别呢?
它们的第一个参数,毋庸置疑,都是传入的执行上下文对象,区别是从第二个参数开始的。call方法的其它参数依次传递给借用的方法作参数,而apply就两个参数,第二个参数为一个数组传递。
简单点,就是:
fun.call(obj, arg1, arg2…) === fun.apply(obj, [arg1, arg2…]) === obj.fun(arg1, arg2…);
咦,call和apply的区别是,参数的传递不同,有什么用呢?
根据它们传递参数的区别,当参数明确的时候,使用call;当传递的参数不明确时,用 apply咯,即传递arguments给apply作为第二个参数。
好了,光说不做没用,我们写个demo看看。
<!DOCTYPE html>
<head>
<title>call&apply</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<script>
function print(name, age, time){
console.log("name: "+ name +" age: "+ age +" time: "+ time );
};
function fn(a, b, c){
//使用call,参数明确
print.call(this,a);
//使用apply,参数明确
print.apply(this,[a, b]);
//使用apply,参数不明确
print.apply(this,arguments);
}
fn('monkey',24,'1992');
</script>
</body>
</html>
执行上述代码,结果如下:

call与apply,这下明白了么?
| 二、bind |
bind,最开始认识它的时候,理解就是改变执行上下文的对象。
比如,当我们使用setTimeout时,默认匿名函数里的this指向的是window,但使用对象的方法时,我想将this指向对象呢,怎么办呢?其中的一个方法就是使用bind。
(关于setTimeout的理解,见“setTimeout那些事儿”)。
如:
<!DOCTYPE html>
<head>
<title>bind</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<script>
var name = 'window';
var obj = {
name:'monkey',
print: function(){
//在这里使用bind,显示地将this指向obj,所以console.log会输出'monkey'
setTimeout(function(){
console.log(this.name);
}.bind(this),100);
}
};
obj.print();
</script>
</body>
</html>
执行上述代码结果为:

好了,既然谈到bind是改变执行上下文中的对象,我靠,那我们怎么不使用call或apply呢?
call或apply不也是改变执行上下文的对象么?
是的,我们将上面的demo修改下,将bind换成call,代码如下:
<!DOCTYPE html>
<head>
<title>bind</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<script>
var name = 'window';
var obj = {
name:'monkey',
print: function(){
setTimeout(function(){
console.log(this.name);
}.call(this)/*在这里将bind换成call*/,100);
}
};
obj.print();
</script>
</body>
</html>
打开chrome调试器,得下结果:

咦,我靠,这不是和bind一样么?
是的,但如果我们将setTimeout的延迟时间,换成2秒,或者更长呢?打开chrome调试器,运行修改后的代码,你就会发现区别,call或apply是立马呈现’monkey’,而bind是在延迟相应时间后,呈现’monkey’。
Why?
因为call或apply是将执行上下文对象换了后,立即执行;而bind是将执行上下文对象换了后,创建一个新函数。
我们再一起写个demo看看。
<!DOCTYPE html>
<head>
<title>bind</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<script>
function fun(){
console.log(this.name);
}
function obj1(){
this.name = 'call||apply';
}
function obj2(){
this.name = 'bind';
}
var o1 = new obj1();
var o2 = new obj2();
fun.call(o1);
fun.bind(o2);
</script>
</body>
</html>
执行上述代码,结果为:

咦,怎么只打印了一个’call||apply’呢?
因为我们在上面的代码中,bind我只是绑定了对象o2,但是它又不立即执行,而是返回一个新函数哦。
我们修改以上代码,手动执行bind返回后的新函数看看。
<!DOCTYPE html>
<head>
<title>bind</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<script>
function fun(){
console.log(this.name);
}
function obj1(){
this.name = 'call||apply';
}
function obj2(){
this.name = 'bind';
}
var o1 = new obj1();
var o2 = new obj2();
fun.call(o1);
//手动调用bind创建的新函数
fun.bind(o2)();
</script>
</body>
</html>
运行代码:

嘿嘿,这下对了吧。
所以,一定要记住bind方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入的第一个参数作为this,即执行上下文对象。
好了,晚安everyone~
call,apply,bind的更多相关文章
- call,apply,bind的用法
关于call,apply,bind这三个函数的用法,是学习javascript这门语言无法越过的知识点.下边我就来好好总结一下它们三者各自的用法,及常见的应用场景. 首先看call这个函数,可以理解成 ...
- JavaScript中call,apply,bind方法的总结。
why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user:"追梦子", fn:f ...
- call(),apply(),bind()与回调
1.call(),apply(),bind()方法 JavaScript 中通过call或者apply用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定 ...
- JS 的 call apply bind 方法
js的call apply bind 方法都很常见,目的都是为了改变某个方法的执行环境(context) call call([thisObj[,arg1[, arg2[, [,.argN]]]] ...
- javascript-this,call,apply,bind简述2
上节我们一起研究了this这个小兄弟,得出一个结论,this指向调用this所在函数(或作用域)的那个对象或作用域.不太理解的朋友可以看看上节的内容,这次我们主要探讨一下call(),apply(), ...
- javascript-this,call,apply,bind简述1
最近在系统的学习面向对象方面的知识,遇到的最大拦路虎就数this的指向,call,apply,bind函数的使用,单独抽出一天时间把这几个烦人的家伙搞定,去学习更深入的内容. 首先介绍一下this的一 ...
- call,apply,bind方法的总结
why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user:"追梦子", fn:f ...
- JavaScript中call,apply,bind方法的总结
原文链接:http://www.cnblogs.com/pssp/p/5215621.html why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之 ...
- call, apply,bind 方法解析
call(), apply(),bind() 三者皆为Function的方法 call(),apply()的作用是调用方法,并改变函数运行时的context(作用上下文) bind() 的作用是引用方 ...
- JS中call,apply,bind方法的总结
why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user: "小马扎", fn: ...
随机推荐
- Salesforce学习笔记(一)
Force平台简介 一.Force平台应用程序的优点1.以数据为中心的应用程序(一个对象就是一个数据库表) 由于该平台以数据库为中心,它让你能够编写以数据为中心的应用程序.以数据为中心的应用程序是基于 ...
- Ubuntu下Android Studio环境搭建
1.JDK安装 a.准备 由于AS(Android Studio)不支持openjdk,需要另行下载oracle jdk,同时官网指出对于64位linux系统,为了能在其上运行32位程序,需要安装一些 ...
- CF2.BC
B. Arpa's obvious problem and Mehrdad's terrible solution time limit per test 1 second memory limit ...
- socket编程学习step1
socket学习参考链接,赞一个:http://blog.csdn.net/hguisu/article/details/7445768 sockets(套接字)编程有三种,流式套接字(SOCK_ST ...
- MyEclipse新建web project和navicat110_mysql_en工具
首先注意几点: 1.eclipse web项目:项目名称不得超过五个字符,要求全部小写,不管变量名.类名.函数名.文件名,在没有特殊理由的时候,不要用下划线,同时表名和类名用两个单词,尽量不要用Stu ...
- web Api 返回json 的两种方式
web api写api接口时默认返回的是把你的对象序列化后以XML形式返回,那么怎样才能让其返回为json呢,下面就介绍两种方法: 方法一:(改配置法) 找到Global.asax文件,在Applic ...
- for循环中的占位 pass
- Python黑帽编程2.5 函数
Python黑帽编程2.5 函数 写了几节的基础知识,真心感觉有点力不从心.这块的内容说实话,看文档是最好的方式,本人的写作水平,真的是找不出更好的写法,头疼.简单带过和没写一样,写详细了和本系列教程 ...
- Hadoop学习笔记—15.HBase框架学习(基础实践篇)
一.HBase的安装配置 1.1 伪分布模式安装 伪分布模式安装即在一台计算机上部署HBase的各个角色,HMaster.HRegionServer以及ZooKeeper都在一台计算机上来模拟. 首先 ...
- .NET中异常处理的最佳实践(译)
本文翻译自CodeProject上的一篇文章,原文地址. 目录 介绍 做最坏的打算 提前检查 不要信任外部数据 可信任的设备:摄像头.鼠标以及键盘 “写操作”同样可能失效 安全编程 不要抛出“new ...