我们在写代码的时候,时常会被this弄的傻傻分不清楚,看源码的时候也经常被call啊apply啊弄的头皮发麻。this到底是什么?本文主要根据书上和实际应用做了一些归纳。一般情况下this有4种绑定规则:

1、默认绑定 - this指向全局变量

举例:

       function baz(){
console.log('a',this.a);
};
var a = 2;
baz(); // a 2

在非严格模式下,我们调用了baz,它没有被任何对象包裹,而是暴露在全局环境中,因此此时它被调用的上下文就是全局环境,所以获取到this.a是2;

2、隐式绑定

这种情况应该是最常见的,我们调用的方法被包含在某个对象中,此时应该找到调用这个方法的对象所处的上下文。

举例:

       function baz(){
console.log('a',this.a);
};
var a = 2;
var obj = {
a: 3,
baz: baz
}
obj.baz(); // a, 3

这个时候,this指向调用baz这个方法的对象obj;所以获取的this.a就是obj.a是3;

思考一下下面的this.a的值又是什么:

      function baz(){
console.log('a',this.a);
};
var a = 2;
var obj = {
a: 3,
baz: baz
}; var obj2 = {
a: 4,
baz: obj.baz
}
obj2.baz();

tips: 对象属性的引用链只有最后一层在调用位置中起作用。

3、显式绑定

这里就是函数可以使用的方法call(obj,param1,param2,...)apply(obj,[param1,param2,...]),它们的作用是我们可以显式的改变函数的上下文(this),参数说明:

  • obj:一个对象,将方法的this指向该对象的this;
  • paramX:参数,两者的表现形式不同
       var a = 2;
function baz(){
console.log('a',this.a);
}; var obj = {
a: 3
}; baz.call(obj); // 改变了this,并执行了函数
// a 3

如果直接baz(),则采用的是第一种规则,这里使用baz.call强行将baz的this指向了obj,所以此时baz中的this是obj;

应用场景:带参数的

        var a = 2;

        function baz(p1, p2) {
console.log(this.a, p1, p2);
}; var obj = {
a: 3
}; var foo = function () {
return baz.apply(obj, arguments)
}; foo("hi,", "heimayu"); // 3 hi, heimayu

4、new绑定

在js中,我们经常使用new来对函数进行构造调用,如下:

       function Foo(a) {
this.a = a;
}; var foo = new Foo(3);
console.log("a", foo.a)

这里,使用new Foo()的时候构造出一个新的对象foo并把它绑定到Foo调用中的this上。

5、优先级

在大多数情况下我们找到函数的调用位置,并判断应用哪种规则,就可以快速找到this;结论:

new绑定 > 显式绑定(call,apply) > 隐式绑定 > 全局默认绑定

6、一些例外

规则是死的,程序是活的,总有例外出现。比如啊:

我不关心this是什么

        function foo(a, b) {
console.log("a:" + a, "b:" + b);
}; foo.apply(null, [1, 2]);
// a:1 b:2

ES6箭头函数

箭头函数不使用上面的规则,而是根据 由外层的作用域来决定它的this

       function foo() {
// return function () {
// console.log('第一种情况', this.a)
// }
return (a)=>{
console.log('第二种情况',this.a)
}
}; var obj1 = {
a: 2
}; var obj2 = {
a: 3
}; var bar = foo.call(obj1);
bar.call(obj2);
// 第一种情况:3
// 第二种情况:2

记住箭头函数的绑定无法被修改!!!因此在执行bar的时调用了foo,而foo中的this是指向到obj1的。

最常见的场景:

        var a = 1;
var obj = {
a:2,
foo: function(){
setTimeout(function(){
console.log(this.a)
},100)
}
}; obj.foo();
// 1

在ES5中,我们想打出的值是2,会这样做:

        var a = 1;
var obj = {
a:2,
foo: function(){
let self = this;
setTimeout(function(){
console.log(self.a)
},100)
}
}; obj.foo();

在ES6中,则可以直接这样:

        var a = 1;
var obj = {
a:2,
foo: function(){
setTimeout(()=>{
console.log(this.a)
},100)
}
}; obj.foo();

理解一下:因为箭头函数中的this,指向了foo,foo的上下文是obj。具体的说:箭头函数会继承外层函数调用的this绑定

关于this的全面解析(call,apply,new)的更多相关文章

  1. 完全解析Array.apply(null, { length: 1000 })

    Array.apply(null, { length: 1000 }) 点击打开视频讲解更加详细 在阅读VueJS教程时有这么段demo code: render: function (createE ...

  2. Spring mybatis源码篇章-NodeHandler实现类具体解析保存Dynamic sql节点信息

    前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-XMLLanguageDriver解析sql包装为SqlSource SqlNode接口类 publi ...

  3. Mybatis源码解析-DynamicSqlSource和RawSqlSource的区别

    XMLLanguageDriver是ibatis的默认解析sql节点帮助类,其中的方法其会调用生成DynamicSqlSource和RawSqlSource这两个帮助类,本文将对此作下简单的简析 应用 ...

  4. Android进阶:七、Retrofit2.0原理解析之最简流程【下】

    紧接上文Android进阶:七.Retrofit2.0原理解析之最简流程[上] 一.请求参数整理 我们定义的接口已经被实现,但是我们还是不知道我们注解的请求方式,参数类型等是如何发起网络请求的呢? 这 ...

  5. Spring源码分析(七)bean标签的解析及注册

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 在上一篇中提到过Spring中的标签包括默认标签和自定义标签两种,而两种 ...

  6. InnoDB recovery过程解析

    本文来自网易云社区. InnoDB如果发生意外宕机了,数据会丢么?对于这个问题,稍微了解一点MySQL知识的人,都会斩钉截铁的回答:不会!为什么?他们也会毫不犹豫的说:因为有重做日志(redo log ...

  7. Mybaits 源码解析 (六)----- 全网最详细:Select 语句的执行过程分析(上篇)(Mapper方法是如何调用到XML中的SQL的?)

    上一篇我们分析了Mapper接口代理类的生成,本篇接着分析是如何调用到XML中的SQL 我们回顾一下MapperMethod 的execute方法 public Object execute(SqlS ...

  8. Gradle--初识

    1.Eclipse从svn导入Gradle项目 1.检出项目的时候不要选新项目,选"做为工作空间中的项目检出",然后点Finish. 2.将项目转为Gradle项目,右键导入的项目 ...

  9. MyBatis 源码分析 - SQL 的执行过程

    * 本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程.该过程本身比较复杂,牵涉到的技术点比较多.包括但不限于 Mapper 接口代理类的生成.接口方法的解析.SQL 语句的解析 ...

  10. MySQL · 引擎特性 · 基于InnoDB的物理复制实现(转载)

    http://mysql.taobao.org/monthly/2016/05/01/ 在开始之前,你需要对InnoDB的事务系统有个基本的认识.如果您不了解,可以参考我之前的几篇关于InnoDB的文 ...

随机推荐

  1. gitLab创建自己的私有库

    一.创建私有库的流程简介 创建一个项目,留着后面的流程3制作私有库 在可以创建私有库的地方创建一个code repository, code repository是代码仓库,我们把代码上传到这个仓库. ...

  2. L05-Linux部署msmtp+mutt发送邮件

    一.前言 首先,得明白发送一封邮件的流程,下面一段理论摘抄自廖雪峰的官网网站https://www.liaoxuefeng.com/article/00137387674890099a71c04005 ...

  3. IntelliJ IDEA 18 周岁,吐血推进珍藏已久的必装插件

    IntelliJ IDEA是目前最好最强最智能的Java IDE,前几天,他刚刚年满18岁.  本文,给大家推荐几款我私藏已久的,自己经常使用的,可以提升代码效率的插件. IDEA插件简介 常见的I ...

  4. 基于iTop4412的FM收音机系统设计(二)

    说明:第一版架构为:APP+JNI(NDK)+Driver(linux),优点是开发简单,周期短,也作为自己的毕业设计 现在更新第二版,FM服务完全植入Android系统中,成为系统服务,架构为:AP ...

  5. VS2010一调试就卡死的问题解决方案 (转)

    前几天我的vs2010突然不能调试了.后来找了很多的解决方案都不能解决问题. 1. 删除所有的bin, debug 2. 重建工程. 3. 重新安装Silverlight的开发包. 还是不行. 最后是 ...

  6. 角色用户权限RBAC

    关于角色.用户.权限的表设计,已经成为经典中的经典,到处都在用,这里只是收录一下: 角色表:{role_id,role_name} 用户表:{user_id,user_name} 权限表:{permi ...

  7. jQuery对象扩展方法(Extend)深度解析

    1.这几天在写自己的Js工具类库,所以在编写对象扩展方法,参考了jQuery的对象扩展方法,在编写该方法前,需要掌握js深拷贝和浅拷贝的相关知识,下面是jQuery3.2.1版本对象扩展方法的源码: ...

  8. JS框架设计之对象扩展一种子模块

    对象扩展 说完了,对象的创建(框架的命名空间的创建)以及如何解决多库之间的命名空间冲突问题之后,接下来,就是要扩展我们的对象,来对框架进行扩展,我们需要一种新功能,将新添加的功能整合到我们定义的对象中 ...

  9. 翻译:WebAssembly简介:我们为什么要关心这个技术? ​​​​

    原文: https://tomassetti.me/introduction-to-webassembly/ WebAssembly简介:我们为什么要关心这个技术? ​​​​ 在对抗js的伟大战斗中有 ...

  10. [中英对照]INTEL与AT&T汇编语法对比

    本文首先对文章Intel and AT&T Syntax做一个中英文对照翻译,然后给出一个简单的例子,再用gdb反汇编后,对INTEL与AT&T的汇编语法进行对照从而加深理解. Int ...