JS this指向问题

tech2022-12-22  58

作用 & 意义 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)