深入理解this,bind、call
首先放一道题:
var a={
a:'haha',
getA: function(){
console.log(this.a);
}
}
var b= {
a:'hello'
}
var getA = a.getA;
var getA2 = getA.bind(a);
function run(fn){
fn();
}
a.getA();//
getA();//
run(a.getA);//
getA2.call(b);//
输出是什么?
可以花几分钟先自己想想。
嘿嘿~
嘿嘿~
嘿嘿~
嘿嘿~
嘿嘿~
嘿嘿~
嘿嘿~
嘿嘿~
嘿嘿~
嘿嘿~
公布答案:
a.getA();//haha
getA();//object
run(a.getA);//object
getA2.call(b);//haha
答对了么?
这里考察了三个点:
形参实参的理解、this的指向、call和bind对this指向的影响。
第一个我相信大家都没问题,这里主要分析后面的两个问题。
this指向问题
this是大部分刚入前端的人都会遇到的坑。
这里通过借鉴网上的文章和自己的理解来总结一下。
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象。
我的理解是,看执行的时候谁在调用就指向谁,但这样理解this也不算完全准确。
这里有三种简单情况:
- 如果函数中的this没有调用它的对象,那么this指向的就是window(严格模式下这种情况的this会为空,即undefined)。
- 如果函数中的this被不包含子对象的对象所调用,那么this指向的就是调用它的对象。
- 如果函数中的this被包含多级对象的对象调用,this指向的也只是它上一级的对象,如下例。
var demoObj = {
a:1,
b:{
fun:function(){
console.log(this.a);
}
}
}
demoObj.b.fun();//undefined
这里this不是指向demoObj对象,而是指向demoObj.b对象,这里找不到demoObj.b对象里的a,所以会输出undefined。
还有三种特殊情况:
- 还是上面的例子,改一下调用函数的方式,如下。
var demoObj = {
a:1,
b:{
fun:function(){
console.log(this.a);
}
}
}
var newFun = demoObj.b.fun;
newFun();//undefined
这里还是得到undefined,但是this的指向却是window,这里的undefined是因为没找到window对象里的a,才输出的undefined。
虽然函数fun是被对象b所调用,但是在将fun赋值给变量newFun的时候并没有执行,newFun的上级对象window,所以最终执行时指向的是window。
- 构造函数用new实例对象时对this的影响。
function Fun(){
this.name = "haha";
}
var stu = new Fun();
console.log(stu.name); //haha
这里之所以对象stu.name可以输出haha,是因为new关键字就是创建一个对象实例,这个stu对象中包含了this.name这个属性,相当于复制但却没有执行。在执行时调用这个函数Fun的是对象stu,所以this指向的就是对象stu。
用new操作符创建对象时发生的事情:
第一步: 创建一个Object对象实例。
第二步: 将构造函数的作用域赋给新对象(因此this就指向了这个新对象)。
第三步: 执行构造函数中的代码(这里的执行并不是真的让this指向哪里,而是为这个新对象添加属性)。
第四步: 返回新生成的对象实例
原本的构造函数是window对象的方法,如果不用new操作符而直接调用,那么构造函数的执行对象就是window,即this指向了window。现在用new操作符后,this就指向了新生成的对象。理解这一步至关重要。
- 有return的函数在new时对this的影响(正常的构造函数是没有return语句),我们先看下面的几个例子。
//例1
function Fun()
{
this.name = 'haha';
return {};
}
var stu = new Fun();
console.log(stu.name); //undefined
//例2
function Fun()
{
this.name = 'haha';
return function(){};
}
var stu = new Fun();
console.log(stu.name); //undefined
//例3
function Fun()
{
this.name = 'haha';
return 123;
}
var stu = new Fun();
console.log(stu.name); //haha
//例4
function Fun()
{
this.name = 'haha';
return undefined;
}
var stu = new Fun();
console.log(stu.name); //haha
可以看出:
如果return的是一个对象,那么this会指向返回的对象,如果return的不是一个对象,那么this还是指向函数的实例。
但是return的是null时比较特殊。虽然null也是对象,但是this还是指向函数的实例。
//例5
function Fun()
{
this.name = 'haha';
return null;
}
var stu = new Fun();
console.log(stu.name); //haha
至此,this就说这么多,相信前三个输出大家都能理解了,接下来说说call和bind。
call和bind
call和apply只有参数不同,这里就只讨论call,因为call和bind参数使用方法是一样的。
- call是动态的改变this的指向,即换个对象执行原对象方法的方法,并立即执行;
- bind是静态改变this的指向,并返回一个修改后的函数。
就拿开始的题目最后一个输出来说:
如果只是使用call的话:
getA.call(b);//hello
getA.call(a);//haha
在执行到这两句时动态改变了this的指向,所以call(b)的输出hello,call(a)的输出haha。
接下来看有bind影响的:
var getA2 = getA.bind(a);
这里getA其实是a.getA大家应该理解,那么getA.bind(a)将this指向a,其实还是返回了a.getA函数赋值给了getA2。注意:其实函数没有变化,但是内部已经将this指向了a。
getA2.call(b);//haha
//相当于a.getA.call(b);
之后call在动态调用时,内部的this已经指向了a,不会再指向b,因此会输出haha。
如果还不是很理解,就将绑定a改成b,如下:
var getA2 = getA.bind(b);
getA2.call(a);//hello
此时无论call里是a还是b,都会输出hello,因为内部的this已经被bind绑定指向b了。
总的来说,call方法是在调用时改变this并立即执行这个函数,bind方法可以先改变函数中的this,之后对应的函数可以在需要的时候再调用。
解决了题,再学一点点。
bind的参数可以在执行的时候再次添加,但是要注意的是,参数需要按照形参的顺序添加。例如:
var demoObj = {
name:"haha",
fun:function(a,b,c){
console.log(a,b,c);
}
}
var newFun = demoObj.fun;
var newFun2 = newFun.bind(demoObj,5);
newFun2(7,9);//5,7,9
看看应该就知道怎么用了。
这里放一个很棒的文章JavaScript 的 this 指向问题深度解析。
好了,谢谢大家阅读~
深入理解this,bind、call的更多相关文章
- 理解Underscore中的_.bind函数
最近一直忙于实习以及毕业设计的事情,所以上周阅读源码之后本周就一直没有进展.今天在写完开题报告之后又抽空看了一眼Underscore源码,发现上次没有看明白的一个函数忽然就豁然开朗了,于是赶紧写下了这 ...
- js学习进阶中-bind()方法
有次面试遇到的,也是没说清楚具体的作用,感觉自己现在还是没有深刻的理解! bind():绑定事件类型和处理函数到DOM element(父元素上) live():绑定事件到根节点上,(document ...
- javascript 中的 bind (编辑中。。。。)
这篇文章说的非常好!http://my.oschina.net/blogshi/blog/265415 我的体会就是,函数中的this,指的是运行时,它是被哪个对象调用的.因为javascrpit的函 ...
- 关于原生js中bind函数的实现
今天继续研究了bind函数的实现,也知道了shim和polyfill的说法,现在总结一下, if (!Function.prototype.bind) { Function.prototype.bin ...
- Boost::bind使用详解
1.Boost::bind 在STL中,我们经常需要使用bind1st,bind2st函数绑定器和fun_ptr,mem_fun等函数适配器,这些函数绑定器和函数适配器使用起来比较麻烦,需要根据是全局 ...
- 依赖注入和Guice理解
理解依赖注入,这篇文章写得非常好,结合spring的依赖注入分析的. http://blog.csdn.net/taijianyu/article/details/2338311/ 大体的意思是: 有 ...
- js中自己实现bind函数的方式
最近由于工作比较忙,好久都没时间静下心来研究一些东西了.今天在研究 call 和 apply 的区别的时候,看到 github 上面的一篇文章,看完以后,感觉启发很大. 文章链接为 https://g ...
- 初学bind
其实项目中还没有用到. 但自己还是想逐步了解一些高级的JS语法,不是为了炫技,也不像找前端的工作. 主要目的是:1.学习设计思想,提升解决问题的能力2.让自己的脑子动起来,别太笨. 简单的几句话总结一 ...
- Computation expressions and wrapper types
原文地址:http://fsharpforfunandprofit.com/posts/computation-expressions-wrapper-types/ 在上一篇中,我们介绍了“maybe ...
- 论JavaScript的作用域
一直以来本人认为想深入了解一门语言,不光是让自己变成撸sir,更需要时间的锤炼.能经得起时间考验的东西更值得拥有.学习和使用Javascript一晃都7年了,最近才感觉自己对他才有顿悟,不知道是否来得 ...
随机推荐
- error: not found: value sqlContext/import sqlContext.implicits._/error: not found: value sqlContext /import sqlContext.sql/Caused by: java.net.ConnectException: Connection refused
1.今天启动启动spark的spark-shell命令的时候报下面的错误,百度了很多,也没解决问题,最后想着是不是没有启动hadoop集群的问题 ,可是之前启动spark-shell命令是不用启动ha ...
- Bootstraptable源码
// @author 文志新 http://jsfiddle.net/wenyi/47nz7ez9/3/ /**关于插件的通用构造 * * 构造函数PluginName($trigger,option ...
- mysql中cast() 和convert()的用法讲解
一.在mysql操作中我们经常需要对数据进行类型转换.此时我们应该使用的是cast()或convert(). 二.两者的对比 相同点:都是进行数据类型转换,实现的功能基本等同 不同点:两者的语法不同, ...
- JMeter监控Slave机器是否执行
netstat -anp | grep 192.168.1.161 | grep 19091 | wc -l http://www.linuxidc.com/Linux/2014-09/106497. ...
- aop日志记录
1.自定义 package cc.mrbird.common.annotation; import java.lang.annotation.ElementType; import java.lang ...
- 手机端-ajax跨域请求滚屏分页
近期做了一个关于信息展示的详情页面,将里面能够提升用户体验的小点写出来 1.当页面请求新的数据,或上传数据的时候 放一个loading.gif的过渡,告诉用户 你的操作已经完成,正在加载中 2.当所有 ...
- Could not locate executable null\bin\winutils.exe in the Hadoop binaries解决方式 spark运行wordcoult
虽然可以正常运行,但是会出异常,现给出解决方法. 1.问题: 2. 问题解决: 仔细查看报错是缺少winutils.exe程序. Hadoop都是运行在Linux系统下的,在windows下ec ...
- JVM笔记(虚拟机各内存的介绍)
JVM笔记 java代码执行分为两部分:javac编译 java执行 代码并不是由上往下执行的,会经过编译期重排序进行优化,存在依赖关系的代码不会被重排序,保证了代码最终执行结果的正确性! j ...
- themeleaf跳转锚链接
<a class="lianjie3" th:href="@{/}+'#requires'"></a>
- 最短路(Floyd)-hdu1317
题目链接:https://vjudge.net/problem/HDU-1317 题目描述: 题意:玩家起始有100个能量点,刚开始在起始房间中,每个房间外有一条单向的路径通往其他房间(一个房间可能通 ...