this,apply,call,bind 超详细合集

前言

之前在学习this关键字的时候,其实一直都是懵懵懂懂。知道答案但是不知道所以。一直想知道为什么是这样?为什么this默认指向全局呢?今天忽然释然了,我又不是开发这门语言的人,我为什么要纠结这些。那今天就来讲讲this的指向的不同场景。
以下是this的所有指向情况

  • 默认绑定:当一个函数独立调用时,不带任何修饰符的调用,该函数的this指向window,默认就是指向window(严格模式下面,this默认绑定就是undefined)

  • 隐式绑定:当一个函数被某个对象所拥有,或者函数被某个上下文对象调用时。该函数中的this指向该上下文对象

  • 隐式丢失:当一个函数被多个对象链式调用时,this指向最近的那个对象(就近原则)。

  • 显示绑定:将函数的this指向特定的对象,call ,apply ,bind

  • new绑定: 构造函数的this指向实例对象

那让我来逐一过一遍所有情况,下面所有代码,要在浏览器中执行,因为nodeJS的全局对象并不是window而是global,所以nodeJS里面打印的是undefined

默认绑定

例题

var a = 3;
function foo() {
    var a = 2;
    foo.a = 1;
    console.log(this.a);
}
foo();

题解

上面一共三个a,分别是

1. 全局中的变量a =3;

2. 函数内定义的变量a =2,

3. 函数foo对象的属性a =1;

再来看看上面这段代码,foo()直接调用,前面或者后面没有加任何修饰符并且是独立调用,那么直接套this默认指向全局window,而在全局定义的var变量会自动挂载在window上面(global上面妹油嗷~~),这意味这console.log(this.a)这个this指向的就是全局中的a,答案打印3。

隐式绑定

例题

var a =4;
var obj = {
    a:3,
    foo:foo
}
function foo() {
    var a = 2;
    foo.a = 1;
    console.log(this.a);
}
obj.foo();

题解

上面一共四个a,分别是

1. 全局中的变量a =4;

2. obj属性a =3;

3. 函数内定义的变量a =2,

4. 函数foo对象的属性a =1;

分析上面代码,foo的执行情况属于第二种隐式绑定,foo是作为obj的属性方法执行的,this就是指向obj,所以答案就是3。

隐式丢失

例题

var a =5;
var obj2 ={
    obj1:obj1,
    a : 4
}
var obj1 = {
    a:3,
    foo:foo
}
function foo() {
    var a = 2;
    foo.a = 1;
    console.log(this.a);
}
obj2.obj1.foo();

题解

上面一共五个a,分别是

1. 全局中的变量a =5;

2. obj2对象中有属性a=4,obj1也是作为obj2的一个属性;

3. obj1属性a =3;

4. 函数内定义的变量a =2,

5. 函数foo对象的属性a =1;

分析上面代码,foo的执行情况属于第三种隐式丢失,foo是作为obj2的属性对象obj1的方法执行的,当一个函数被多个对象链式调用时,this指向最近的那个对象(就近原则),所以this指向的是obj1,答案就为3。

显示绑定(call,apply,bind)

例题

var a =3;
var obj = {
    a :2
}
function foo(){
    console.log(this.a);
}
foo();
foo.call(obj);
foo.apply(obj);
foo.bind(obj)();

题解

上面一共两个a,分别是

1. 全局中的变量a =3;

2. obj对象中有属性a=2

分析上面代码,一共有四个foo的执行,

  • foo(),这个是默认绑定,this直接指向的是全局,所以打印的是3

  • foo.call(obj),这个是显示绑定,功能就是让调用call的方法的this指向传进来的对象参数,这里是foo调用的call方法,传入的参数是obj,所以foo内部的this指向的是obj,打印的是2

  • foo.apply(obj),这个和call使用原理方法基本一致,唯一不同就是在于callapply传入的第一个参数都是this要指向的对象,而后面的参数,call是一个个单独参数,而apply是一个数组,所以这里是foo调用的apply方法,this指向的是对象obj,所以打印的是2

  • foo.bind()(obj),这个和call还有apply使用原理方法就有点不一样了,不过原理基本都是让调用这个方法的this指向传入的参数对象。但是bind会返回一个已绑定this为参数对象的新函数,您需要先保存这个新函数,然后再调用它。我这里是直接调用没有保存,所以打印的依然是2

new绑定

例题

function Person(age){
    this.age =age;
}
let person =new Person(18);
console.log(person.age);

题解

这里定义了一个Person函数,当作一个类,new了一个person实例,打印的结果为18。想知道详细原理的可以看看我的这篇文章一篇文章,new,原型,单例设计模式全部搞定! - 掘金 (juejin.cn),这里简单描述就是,

  1. 创建一个新的对象,这里用obj来形容
  2. obj.__proto__ = Person.prototype,执行复制代码;
  3. 返回新的对象
    所以这里的this指向的是new创建出来的实例对象,打印的值就为18.

结束语

到此为止this的所有情况全部列举出来了,本次分享就全部到此结束,如果大家还有什么补充或者纠正,欢迎评论区评论,谢谢大家>_<.

  • 28
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

绯雨934

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值