JavaScript逐点突破系列之this是什么?了解完这7点很多疑惑都解决

本文详细解释了JavaScript中this的关键字在不同情境下的行为,包括函数嵌套、构造函数调用、call/apply/bind方法以及箭头函数的this指向规则。通过实例和流程图展示了this指向如何受上下文影响,对于理解和调试JavaScript代码至关重要。
摘要由CSDN通过智能技术生成

y: {

x: 3,

fn: function() {

console.log(this); // Object {x: 3, fn: function}

console.log(this.x); // 3

}

}

}

obj.y.fn();

为什么结果不是 2 呢,因为在这种情况下记住一句话:this 始终会指向直接调用函数的上一级对象,即 y,上面例子实际执行的是下面的代码。

var y = {

x: 3,

fn: function() {

console.log(this); // Object {x: 3, fn: function}

console.log(this.x); // 3

}

}

var x = 1

var obj = {

x: 2,

y: y

}

obj.y.fn();

对象可以嵌套,函数也可以,如果函数嵌套,this 会有变化吗?我们通过下面代码来探讨一下。

var obj = {

y: function() {

console.log(this === obj); // true

console.log(this); // Object {y: function}

fn();

function fn() {

console.log(this === obj); // false

console.log(this); // Window 全局对象

}

}

}

obj.y();

在函数 y 中,this 指向了调用它的上一级对象 obj,这是没有问题的。但是在嵌套函数 fn 中,this 并不指向 obj。嵌套的函数不会从调用它的函数中继承 this,当嵌套函数作为函数调用时,其 this 值在非严格模式下指向全局对象,在严格模式是 undefined,所以上面例子实际执行的是下面的代码。

function fn() {

console.log(this === obj); // false

console.log(this); // Window 全局对象

}

var obj = {

y: function() {

console.log(this === obj); // true

console.log(this); // Object {y: function}

fn();

}

}

obj.y();

情况三:作为构造函数调用

我们可以使用 new 关键字,通过构造函数生成一个实例对象。此时,this 便指向这个新对象

var x = 1;

function Fn() {

this.x = 2;

console.log(this); // Fn {x: 2}

}

var obj = new Fn(); // obj和Fn(…)调用中的this进行绑定

console.log(obj.x) // 2

使用new来调用Fn(..)时,会构造一个新对象并把它(obj)绑定到Fn(..)调用中的this。还有值得一提的是,如果构造函数返回了非引用类型(string,number,boolean,null,undefined),this 仍然指向实例化的新对象。

var x = 1

function Fn() {

this.x = 2

return {

x: 3

}

}

var a = new Fn()

console.log(a.x) // 3

因为Fn()返回(return)的是一个对象(引用类型),this 会指向这个return的对象。如果return的是一个非引用类型的值呢?

var x = 1

function Fn() {

this.x = 2

return 3

}

var a = new Fn()

console.log(a.x) // 2

情况四:call 和 apply 方法调用

如果你想改变 this 的指向,可以使用 call 或 apply 方法。它们的第一个参数都是指定函数运行时其中的this指向。如果第一个参数不传(参数为空)或者传 null 、undefined,默认 this 指向全局对象(非严格模式)或 undefined(严格模式)。

var x = 1;

var obj = {

x: 2

}

function fn() {

console.log(this);

console.log(this.x);

}

fn.call(obj)

// Object {x: 2}

// 2

fn.apply(obj)

// Object {x: 2}

// 2

fn.call()

// Window 全局对象

// 1

fn.apply(null)

// Window 全局对象

// 1

fn.call(undefined)

// Window 全局对象

// 1

使用 call 和 apply 时,如果给 this 传的不是对象,JavaScript 会使用相关构造函数将其转化为对象,比如传 number 类型,会进行new Number()操作,如传 string 类型,会进行new String()操作,如传 boolean 类型,会进行new Boolean()操作。

function fn() {

console.log(Object.prototype.toString.call(this))

}

fn.call(‘love’) // [object String]

fn.apply(1) // [object Number]

fn.call(true) // [object Boolean]

call 和 apply 的区别在于,call 的第二个及后续参数是一个参数列表,apply 的第二个参数是数组。参数列表和参数数组都将作为函数的参数进行执行。

var x = 1

var obj = {

x: 2

}

function Sum(y, z) {

console.log(this.x + y + z)

}

Sum.call(obj, 3, 4) // 9

Sum.apply(obj, [3, 4]) // 9

情况五:bind 方法调用

调用 f.bind(someObject) 会创建一个与 f 具有相同函数体和作用域的函数,但是在这个新函数中,新函数的 this 会永久的指向 bind 传入的第一个参数,无论这个函数是如何被调用的。

var x = 1

var obj1 = {

x: 2

};

var obj2 = {

x: 3

};

function fn() {

console.log(this);

console.log(this.x);

};

var a = fn.bind(obj1);

var b = a.bind(obj2);

fn();

// Window 全局对象

// 1

a();

// Object {x: 2}

// 2

b();

// Object {x: 2}

// 2

a.call(obj2);

// Object {x: 2}

// 2

在上面的例子中,虽然我们尝试给函数 a 重新指定 this 的指向,但是它依旧指向第一次 bind 传入的对象,即使是使用 call 或 apply 方法也不能改变这一事实,即永久的指向 bind 传入的第一次参数。

情况六:箭头函数中this指向

值得一提的是,从ES6 开始新增了箭头函数,先来看看MDN 上对箭头函数的说明

An arrow function expression has a shorter syntax than a function expression and does notbind its ownthis,arguments,super, ornew.target. Arrow functions are always anonymous. These function expressions are best suited for non-method functions, and they cannot be used as constructors.

这里已经清楚了说明了,箭头函数没有自己的this绑定。箭头函数中使用的this,其实是直接包含它的那个函数或函数表达式中的this。在前面情况二中函数嵌套函数的例子中,被嵌套的函数不会继承上层函数的 this,如果使用箭头函数,会发生什么变化呢?

var obj = {

y: function() {

console.log(this === obj); // true

console.log(this); // Object {y: function}

var fn = () => {

console.log(this === obj); // true

console.log(this); // Object {y: function}

}

fn();

}

}

obj.y()

和普通函数不一样,箭头函数中的 this 指向了 obj,这是因为它从上一层的函数中继承了 this,你可以理解为箭头函数修正了 this 的指向。所以箭头函数的this不是调用的时候决定的,而是在定义的时候处在的对象就是它的this

换句话说,箭头函数的this看外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window

var obj = {

y: () => {

console.log(this === obj); // false

console.log(this); // Window 全局对象

var fn = () => {

console.log(this === obj); // false

console.log(this); // Window 全局对象

}

fn();

}

}

obj.y()

上例中,虽然存在两个箭头函数,其实this取决于最外层的箭头函数,由于obj是个对象而非函数,所以this指向为Window全局对象。

同 bind 一样,箭头函数也很“顽固”,我们无法通过 call 和 apply 来改变 this 的指向,即传入的第一个参数被忽略

var x = 1

var obj = {

x: 2

}

var a = () => {

console.log(this.x)

console.log(this)

}

a.call(obj)

// 1

// Window 全局对象

a.apply(obj)

// 1

// Window 全局对象

上面的文字描述过多可能有点干涩,那么就看以下的这张流程图吧,我觉得这个图总结的很好,图中的流程只针对于单个规则。

小结


本篇文章介绍了 this 指向的几种情况,不同的运行环境和调用方式都会对 this 产生影响。总的来说,函数 this 的指向取决于当前调用该函数的对象,也就是执行时的对象。在这一节中,你需要掌握:
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

前15.PNG

前16.PNG

由于文档内容过多,为了避免影响到大家的阅读体验,在此只以截图展示部分内容,详细完整版的JavaScript面试题文档,或更多前端资料可以点此处免费获取

开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

[外链图片转存中…(img-feDG18L0-1713506728982)]

[外链图片转存中…(img-NUec4bTx-1713506728982)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-x2YKaQPp-1713506728983)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

[外链图片转存中…(img-x9LvPD80-1713506728983)]

最后

[外链图片转存中…(img-Df243rI9-1713506728983)]

[外链图片转存中…(img-q6aXMZgZ-1713506728984)]

由于文档内容过多,为了避免影响到大家的阅读体验,在此只以截图展示部分内容,详细完整版的JavaScript面试题文档,或更多前端资料可以点此处免费获取

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值