Javascript - this

本文详细介绍了JavaScript中this的调用分类,包括独立调用、隐式调用(如作为对象方法调用)、显示绑定(call、apply、bind)、new调用以及箭头函数。讨论了this的指向规则和调用优先级,并通过实例解析了this如何根据函数的执行环境确定其值。此外,还解释了new操作符的工作原理以及this在内存数据结构中的作用。
摘要由CSDN通过智能技术生成

this是在函数运行时,在函数体内部自动生成的一个对象,并只能在函数体内部使用。

总的来说,this 就是函数运行时所在的环境对象

1,调用分类

1.1,独立调用

1,纯粹的函数调用

函数在浏览器全局环境中被直接调用

  • 非严格模式下 this 指向 window
  • 严格模式下 this 指向 undefined
function f1() {
  console.log(this) // window
}

function f2() {
  'use strict'
  console.log(this) // undefined
}

2,匿名函数调用

setTimeout(function () {
  console.log(this) // window
})

setTimeout(function () {
  'use strict'
  console.log(this) // 注意是 window
})

1.2,隐式调用

作为对象的方法调用

在执行函数时,如果函数的 this 是被上一级的对象调用,那么this指向上一级对象。

举例 1:

const person = {
  name: '下雪天的夏风',
  brother: {
    name: '路飞',
    fn: function () {
      return this.name
    }
  }
}

console.log(person.brother.fn()) // 路飞

举例 2:

const obj1 = {
  name: '1',
  fn: function () {
    return this.name
  }
}

const obj2 = {
  name: '2',
  fn: function () {
    return obj1.fn()
  }
}

const obj3 = {
  name: '3',
  fn: obj1.fn
}

const obj4 = {
  name: '4',
  fn: function () {
    const fn = f1.fn
    return fn()
  }
}

var name = 'global'

console.log(obj1.fn()) // 1
console.log(obj2.fn()) // 1
console.log(obj3.fn()) // 3
console.log(obj4.fn()) // global
  1. this指向上一级对象obj1
  2. this指向上一级对象obj1
  3. obj1.fn 是函数的引用,obj3.fn()this指向上一级对象obj3
  4. const fn = f1.fn赋值后,fn()变成独立调用,this指向window

隐式丢失

隐式绑定的函数丢失了绑定的对象,实质上都是变成了独立调用this指向了window

es6 的 class 类中,默认开启严格模式,所以出现隐式丢失的情况时,thisundefined,通过 this 访问属性会直接报错。

const obj = {
  name: '下雪天的夏风',
  foo: function () {
    console.log(this.name)
  }
}

下面这4种,都可以理解为将 obj.foo 赋值给一个新的变量来调用。

1,函数通过别名调用

const bar = obj.foo
bar()

2,参数传递

function doFoo(foo) {
  foo()
}
doFoo(obj.foo)

3,匿名函数调用

setTimeout(obj.foo)

4,条件判断后调用

(false || obj.foo)()

1.3,显示绑定调用

call,apply,bind 的调用

三者异同点:

const targetObj = {}
function fn() {}

fn.call(targetObj, 'arg1', 'arg2')

fn.apply(targetObj, ['arg1', 'arg2'])

fn.bind(targetObj, 'arg1', 'arg2')() // 返回一个新函数来调用。

如果第 1 个参数是null | undefined,此时 this 绑定给 window

1.4,new 调用

作为构造函数调用

构造函数:可以通过这个函数生成有一个新的对象,此时 this 指向这个新对象。

function test() {
  this.x = 1
}

const obj = new test()
obj.x // 1

1,new 做了什么

对于构造函数Foo来说,执行 new Foo() 会进行如下操作

  1. 创建一个新对象 const context = {}
  2. 使 context.__proto__ = Foo.prototype

前 2 步可以合并为

const context = Object.create(Foo.prototype)
  1. 改变 Foothis指向新对象context,并执行Foo
const result = Foo.apply(context, arguments)
  1. 如果执行结果是对象,则直接返回,否则返回创建的新对象 context
return typeof result === 'object' && result !== null ? result : context

2,new 调用的返回值

new 命令始终返回一个对象。

  • 构造函数内部有return语句,并且后面跟着对象,则会返回这个对象。否则不管这个return语句,返回this对象。
  • 构造函数内部没有return语句,则返回this对象。

1.5,箭头函数调用

箭头函数没有自己的this对象,内部的this就是定义时上层作用域中的this
也就是说,箭头函数内部的this指向是固定的。

function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 }); // id: 42

2,调用优先级

new > 显示绑定 > 隐式

显示绑定 > 隐示,比较容易理解。

我们来举个 new > 显示绑定 的例子:

function foo (a) {
    this.a = a
}
const obj1 = {}

var bar = foo.bind(obj1)
bar(2)
console.log(obj1.a)  // 2

相比于bar()直接调用,通过 new 调用时,返回的实例已经与 obj1 解绑。

var baz = new bar(3)
console.log(baz.a)  // 3

3,this 原理

我们在一开始说:this 就是函数运行时所在的环境对象

以下面的代码为例(隐示丢失):

const obj = {
  name: '下雪天的夏风',
  foo: function () {
    console.log(this.name)
  }
}
var name = '2'

obj.foo() // '下雪天的夏风'
const foo = obj.foo
foo() // 2

所以,

  • 对于obj.foo来说,foo运行在obj环境,所以this指向obj
  • 对于foo来说,foo运行在全局环境,所以this指向全局环境。

那为什么会这样?

内存的数据结构

const obj = { name: '下雪天的夏风' }

将一个对象赋值给变量 obj 时:js 引擎会先在内存中生成对象{ name: '下雪天的夏风' },再将对象的内存地址赋值给变量obj

之后在读取obj.name 时,js引擎先在obj拿到内存地址——>从内存地址获取原始对象——>从对象获取name属性。

函数

而属性的值可能是一个函数:

const obj = { foo: function() {} }

当对象的属性是函数时:js引擎会将函数单独保存在内存中,然后再将函数的地址赋值给foo属性。

obj: {
  foo: 函数的地址
}

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

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

const foo = function () {};
const obj = { foo };

// 单独执行
foo ()

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

以上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

下雪天的夏风

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

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

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

打赏作者

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

抵扣说明:

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

余额充值