文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

JavaScript中this的绑定你知道几种?

2023-02-08 12:03

关注

执行上下文

我们知道执行上下文分为两种:全局上下文和函数上下文(我的这篇文章对于执行上下文有讲解还对执行上下文和作用域迷糊吗?)。全局上下文只有一个,函数执行上下文是在函数调用的时候创建的。

每个执行上下文都有三个属性:

this到底是什么呢

this是在运行时绑定的,并不是在编写时绑定的,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何的关系,只取决于函数的调用方式。

调用位置

要理解this的绑定过程,首先要理解调用位置。调用位置就是函数的调用的位置(不是声明的位置)。所以我们要先来分析调用栈(也就是执行上下文栈)。我们先来看一段代码。

function baz() {
  console.log("baz")
  bar()
}
function bar() {
  console.log("bar")
  foo()
}
function foo() {
  console.log("foo")
}
baz()

当代码执行到foo(),进入foo的函数体,此时当前的调用栈为:

ECStack = [
    fooContext, // foo
    barContext, // bar
    bazContext, // baz
    globalContext, // 全局
]

通过调用栈我们就可以很清晰的找到函数的调用位置。baz在全局调用,bar在baz里调用,foo在bar里调用。

那函数在执行的时候是如何决定this的绑定对象的呢?

绑定规则

通过绑定规则决定this的绑定对象。

默认绑定

最常用的调用类型:独立函数调用。

function foo(){
    console.log(this.a) // 2
}

var a = 2;
foo()

函数调用的时候,使用了this的默认绑定,因此this指向全局对象。

那么我们怎么知道这里应用了默认绑定呢?可以通过分析调用位置来看看 foo() 是如何调用的。在代码中,foo()是直接使用不带任何修饰的函数引用进行调用的,因此只能使用默认绑定,无法应用其他规则。

所以,在全局环境中调用一个函数,函数内部的this指向的是全局变量window。

隐式绑定

function foo() {
    console.log( this.a );
}

var obj = {
    a: 2,
    foo: foo
};

obj.foo(); // 2

这段代码我们看到foo的声明位置是在全局的,但是它被当做引用属性添加到了obj中。调用位置使用obj上下文引用函数。当foo被调用时候,它是被obj对象所包含的,落脚点指向obj对象。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。

通过一个对象调用其内部的一个方法,该方法的执行上下文中的this指向对象本身

我们看个特殊的例子

function foo() {
  console.log(this.a)
}

var obj = {
  a: 2,
  foo
}

var bar = obj.foo
var a = "mick"
bar() // mick

bar是obj.foo的一个引用,但是实际上,它引用的是foo函数本身,因此此时bar()其实是一个不带任何修饰的函数调用,因此应用了默认绑定。

我们再看另一种情况

function foo() {
  console.log(this.a)
}

function doFoo(fn) {
  fn()
}

var obj = {
  a: 2,
  foo
}

var a = "mick"

doFoo(obj.foo) // mick

嵌套函数中的this 不会从外层函数中继承。this永远指向最后调用它的那个对象

显示绑定

可以使用call、apply或bind方法。如果对这三个方法的实现原理感兴趣可以看看这篇手写call、apply、bind

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

foo.call(obj) // 2

通过call方法,可以在调用foo时候,强制把它的this绑定到obj上。

new绑定

这里我们先说一下new来调用函数会发生哪些事情

function foo(a){
    this.a = a
}
var bar = new foo(2)
console.log(bar.a)

使用new来调用foo时,我们会构造一个新对象并把它绑定到foo调用中的this上。

特例

function foo() {
  console.log(this.a)
}

var a = 2
var o = { a: 3, foo: foo }
var p = { a: 4 }

o.foo() // 3
;(p.foo = o.foo)() // 2

赋值表达式p.foo = o.foo的返回值是目标函数的引用,因此调用位置是foo()而不是p.foo()或者o.foo()。所以这里是默认绑定。

面试题

下面我们看个面试题吧

var name = 'window'
var person1 = {
  name: 'person1',
  foo1: function () {
    console.log(this.name)
  },
  foo2: () => console.log(this.name),
  foo3: function () {
    return function () {
      console.log(this.name)
    }
  },
  foo4: function () {
    return () => {
      console.log(this.name)
    }
  }
}
var person2 = { name: 'person2' }

person1.foo1()
person1.foo1.call(person2)

person1.foo2()
person1.foo2.call(person2)

person1.foo3()()
person1.foo3.call(person2)()
person1.foo3().call(person2)

person1.foo4()()
person1.foo4.call(person2)()
person1.foo4().call(person2)

我们一个个来解析一下。

简单的谈了谈this的绑定,欢迎留言你的问题,大家一起学习一起进步!!!

到此这篇关于JavaScript中this的绑定你知道几种?的文章就介绍到这了,更多相关JavaScript this绑定内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯