一文读懂Js中的this指向

本文详细解析了JavaScript中的this关键字,包括它的实质、不同使用场合下的指向,如全局环境、构造函数、对象方法、数组方法、原型链、DOM事件处理函数、setTimeout/Interval、箭头函数。此外,还介绍了Function.prototype.call()、apply()和bind()这三个方法,用于改变或固定this的指向,并提供了手动实现这些方法的示例。通过对this深入理解,能更好地掌握JavaScript中的函数调用和对象操作。
摘要由CSDN通过智能技术生成

前言

this关键字是一个非常重要的语法点。毫不夸张地说,不理解它的含义,大部分开发任务都无法完成。

简单说,this就是属性或方法“当前”所在的对象。

this.property

上面代码中,this就代表property属性当前所在的对象。

下面是一个实际的例子。

var person = {
   
  name: '张三',
  describe: function () {
   
    return '姓名:'+ this.name;
  }
};

person.describe()
// "姓名:张三"

上面代码中,this.name表示name属性所在的那个对象。由于this.name是在describe方法中调用,而describe方法所在的当前对象是person,因此this指向personthis.name就是person.name

由于对象的属性可以赋给另一个对象,所以属性所在的当前对象是可变的,即this的指向是可变的。

var A = {
   
  name: '张三',
  describe: function () {
   
    return '姓名:'+ this.name;
  }
};

var B = {
   
  name: '李四'
};

B.describe = A.describe;
B.describe() // "姓名:李四"

上面代码中,A.describe属性被赋给B,于是B.describe就表示describe方法所在的当前对象是B,所以this.name就指向B.name

只要函数被赋给另一个变量,this的指向就会变。

var A = {
   
  name: '张三',
  describe: function () {
   
    return '姓名:'+ this.name;
  }
};

var name = '李四';
var f = A.describe;
f() // "姓名:李四"

上面代码中,A.describe被赋值给变量f,内部的this就会指向f运行时所在的对象(本例是顶层对象,在浏览器中就是window),因此name为全局name的值。

实质

JavaScript 语言之所以有 this 的设计,跟内存里面的数据结构有关系。

var obj = {
    foo:  5 };

上面的代码将一个对象赋值给变量obj。JavaScript 引擎会先在内存里面,生成一个对象{ foo: 5 },然后把这个对象的内存地址赋值给变量obj。也就是说,变量obj是一个地址(reference)。后面如果要读取obj.foo,引擎先从obj拿到内存地址,然后再从该地址读出原始的对象,返回它的foo属性。

原始的对象以字典结构保存,每一个属性名都对应一个属性描述对象。举例来说,上面例子的foo属性,实际上是以下面的形式保存的。

{
   
  foo: {
   
    [[value]]: 5
    [[writable]]: true
    [[enumerable]]: true
    [[configurable]]: true
  }
}

注意,foo属性的值保存在属性描述对象的value属性里面。

这样的结构是很清晰的,问题在于属性的值可能是一个函数

var obj = {
    foo: function () {
   } };

这时,引擎会将函数单独保存在内存中,然后再将函数的地址赋值给foo属性的value属性。

{
   
  foo: {
   
    [[value]]: 函数的地址
    ...
  }
}

由于函数是一个单独的值,所以它可以在不同的环境(上下文)执行。

var f = function () {
   };
var obj = {
    f: f };

f() // 单独执行

obj.f() // obj 环境执行

JavaScript 允许在函数体内部,引用当前环境的其他变量。

var f = function () {
   
  console.log(x);
};

上面代码中,函数体里面使用了变量x。该变量由运行环境提供。

现在问题就来了,由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境

var f = function () {
   
  console.log(this.x);
}

上面代码中,函数体里面的this.x就是指当前运行环境的xthis 就是指代当前运行在什么环境。

var f = function () {
   
  console.log(this.x);
}

var x = 1;
var obj = {
   
  f: f,
  x: 2,
};

// 单独执行
f() // 1

// obj 环境执行
obj.f() // 2

上面代码中,函数f在全局环境执行,this.x指向全局环境的x;在obj环境执行,this.x指向obj.x。参考视频讲解:进入学习

使用场合

this主要有以下几个使用场合。

全局环境下

  • 在浏览器全局环境下,this 始终指向全局对象(window), 无论是否严格模式;
this === window // true

  • 普通函数,非严格模式下,指向window严格模式下,指向 undefined
function f() {
   
    console.log(this === window);
}
f() // true

function f() {
   
    'use strict';
    console.log(this === undefined);
}
f() // true

构造函数中

构造函数中的this,指的是实例对象。

var Obj = function (p) {
   
  this.p = p;
};

上面代码定义了一个构造函数Obj。由于this指向实例对象,所以在构造函数内部定义this.p,就相当于定义实例对象有一个p属性。

var o = new Obj('Hello World!');
o.p // "Hello World!"

对象的方法中

如果对象的方法里面包含thisthis的指向就是方法运行时所在的对象。该方法赋值给另一个对象,就会改变this的指向。

但是,这条规则很不容易把握。请看下面的代码。

var obj ={
   
  foo: function () {
   
    console.log(this);
  }
};

obj.foo() // obj

上面代码中,obj.foo方法执行时,它内部的this指向obj

但是,下面这几种用法,都会改变this的指向。

// 情况一
(obj.foo = obj.foo)() // window
// 情况二
(false || obj.foo)() // window
// 情况三
(1, obj.foo)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值