JS this指向问题

作用 & 意义
this关键字具有一种指向作用,类似于指针的作用,可以为你的变量或方法提供一个指向。
a.如果是一般函数,this指向全局对象window;

b.在严格模式下"use strict",为undefined.

c.对象的方法里调用,this指向调用该方法的对象.

d.构造函数里的this,指向创建出来的实例.

多数情况下,this 指向调用它所在方法的那个对象。
当调用方法没有明确对象时,this 就指向全局对象。在浏览器中,指向 window;在 Node 中,指向 Global。(严格模式下,指向 undefined)。
this 的指向是在调用时决定的,而不是在书写时决定的。这点和闭包恰恰相反。
不管方法被书写在哪个位置,它的 this 只会跟着它的调用方走。

特殊情境下的 this 指向
在三种特殊情境下,this 会 100% 指向 window:

1、立即执行函数(IIFE)
2、setTimeout 中传入的函数
3、setInterval 中传入的函数

“危险” 的严格模式
1、普通函数中的 this 在严格模式下的表现
所谓 “普通函数” ,这里我们是相对于箭头函数来说的。在非严格模式下,直接调用普通函数时,正如我们开篇所说,函数中的 this 默认指向全局变量(window 或 global),而在严格模式下,this 将保持它被指定的那个对象的值,所以,如果没有指定对象,this 就是 undefined 。
2、全局代码中的 this 在严格模式下的表现
像这样处于全局代码中的 this, 不管它是否处于严格模式下,它的 this 都指向 Window(这点要特别注意,区分度非常高,很多同学面试的时候会误以为这里也是 undefined )。

隐式丢失
隐式丢失就是指隐式绑定的函数丢失绑定对象,从而默认绑定到全局或者undefined(取决于是否使用严格模式)。
1、为函数调用创建别名
2、传入回调函数
3、传入语言内置的函数

箭头函数
箭头函数中的 this 比较特别,它和严格模式、非严格模式啥的都没关系。它和闭包很相似,都是认“死理”—— 认“词法作用域”的家伙。所以说箭头函数中的 this,和你如何调用它无关,由你书写它的位置决定(和普通函数的 this 规则恰恰相反~)。
因为箭头函数的 this 指向是静态的,“一次便是一生”。

改变this指向
改变 this 的指向,我们主要有两条路:
1、通过改变书写代码的方式做到(比如上一节提到的箭头函数)。
当我们将普通函数改写为箭头函数时,箭头函数的 this 会在书写阶段(即声明位置)就绑定到它父作用域的 this 上。无论后续我们如何调用它,都无法再为它指定目标对象。
2、显式地调用一些方法来帮忙。
改变 this 指向,我们常用的是 call、 apply 和 bind 方法。
在这里插入图片描述
call、apply 和 bind,都是用来改变函数的 this 指向的。

call、apply 和 bind 之间的区别比较大,前者在改变 this 指向的同时,也会把目标函数给执行掉;后者则只负责改造 this,不作任何执行操作。

call 和 apply 之间的区别,则体现在对入参的要求上。前者只需要将目标函数的入参逐个传入即可,后者则希望入参以数组形式被传入。

call方法的模拟

Function.prototype.myCall = function(context, ...args) {
    // step1: 把函数挂到目标对象上(这里的 this 就是我们要改造的的那个函数)
    context.func = this
    // step2: 执行函数,利用扩展运算符将数组展开
    context.func(...args)
    // step3: 删除 step1 中挂到目标对象上的函数,把目标对象”完璧归赵”
    delete context.func
}

apply方法的模拟

Function.prototype.myApply = function (context, arr) {
  context.func = this
  context.func(...arr)
  delete context.func
}

bind方法的模拟

Function.prototype.bind1 = function () {
            //将参数拆解为数组
            const args = Array.prototype.slice.call(arguments);

            //获取 this (数组第一项)
            const t = args.shift();

            //fn1.bind(...) 中的 fn1
            const self = this;

            //返回一个函数
            return function () {
                return self.apply(t, args);
            }
        }

this的四种绑定规则
1、默认绑定
对于默认绑定来说,决定this绑定对象的是函数体是否处于严格模式,严格指向undefined,非严格指向全局对象。
2、隐式绑定
函数在调用位置,是否有上下文对象,如果有,那么this就会隐式绑定到这个对象上。
隐式绑定丢失的问题:实际上就是函数调用时,并没有上下文对象,只是对函数的引用,所以会导致隐式绑定丢失。
3、显式绑定
如果单纯使用隐式绑定肯定没有办法得到期望的绑定,幸好我们还可以在某个对象上强制调用函数,从而将this绑定在这个对象上。
规则:我们可以通过apply、call、bind将函数中的this绑定到指定对象上。
4、new绑定
在js中,实际上并不存在所谓的‘构造函数‘,只有对于函数的‘构造调用‘。
new的时候会做哪些事情:
1.创建一个全新的对象。
2.这个新对象会被执行 [[Prototype]] 连接。
3.这个新对象会绑定到函数调用的this。
4.如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
规则:使用构造调用的时候,this会自动绑定在new期间创建的对象上。

this四种绑定规则的优先级
显式绑定和new绑定无法直接比较(会报错),默认绑定是不应用其他规则之后的兜底绑定所以优先级最低,最后的结果是:

显式绑定 > 隐式绑定 > 默认绑定

new绑定 > 隐式绑定 > 默认绑定

箭头函数的this指向不会使用上述的四条规则。
箭头函数的this规则:
1.箭头函数中的this继承于它外面第一个不是箭头函数的函数的this指向。
2.箭头函数的 this 一旦绑定了上下文,就不会被任何代码改变。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值