那些年你想知道的this

1.为什么要真正理解this?

因为在JavaScript之中,this是动态绑定的,或者称为运行期绑定的,它极为灵活但是正因为如此它绑定的函数很多人来说并不清楚,这需要真正的理解才能更好的使用它。

在使用this的过程中我们有一句话是这么说的:谁调用了该函数,那么this就指向谁。这句话在大部分情况下都是适用的,我们后面也将根据这句话进行探讨。

2.函数在不同情况下this的值

2.1函数作为普通函数调用

javascript 复制代码
//非严格模式下
function fn1() {
    return this
}
//在浏览器中
fn1() === window
//在Node中
fn1() === global

//严格模式下
"use strict";
function fn2() {
    return this
}
fn2() === undefined //true

fn1()等价于window.fn1()或者 global.fn1() 这样的话就不难理解为什么它们的指向会是全局变量了,只是严格模式禁止了该行为,所以返回了undefined(严格模式如果显示调用也不会显示undefined)。

2.2作为对象的方法调用

javascript 复制代码
var name = 'window'
var obj = {
    name: 'obj',
    fn1: function() {
        console.log(this.name)
    }
}
obj.fn1() // obj

这里是对象的显式调用,很明显我们能看到obj直接调用了fn1方法,所以this指向的就是obj。

javascript 复制代码
var name = 'window'
var obj = {
    name: 'obj',
    fn1: function() {
         console.log(this.name)
    }
}
var fn2= obj.fn1
fn2()  // window

从这里我们可以看出,虽然fn1是在obj里面定义的,但是最终赋值给了fn2,当fn2执行的时候this的指向就不再是obj了,而是window,类似于2.1的例子。

2.3关于setTimeout和setInterVal

2.3.1 基本使用

javascript 复制代码
var name = 'window'
var obj = {
    name: 'obj',
    fn1: function() {
        setTimeout(function() {
            console.log(this.name)
        },0)
    }
}
obj.fn1() // window

//严格模式下
"use strict";
var name = 'window'
var obj = {
    name: 'obj',
    fn1: function() {
	    setTimeout(function() {
	        console.log(this.name)
	    },0)
    }
}
obj.fn1() // window

setTimeout和setInterVal的this指向是window(全局对象),这是因为调用的代码运行在与所在函数完全分离的执行环境上导致的。

而且值得注意的是即使是在严格模式下,setTimeout的回调函数里面的this仍然默认指向window对象, 并不是undefined。

现在我们对上述的代码进行修改,使其能够正确的指向obj:

2.3.2 解决方案一

javascript 复制代码
// 解决方案一:使用箭头函数
var name = 'window'
var obj = {
    name: 'obj',
    fn1: function() {
      setTimeout(() => {
          console.log(this.name)
      },0)
    }
}
obj.fn1() // obj 

我们知道,箭头函数是从自己的作用域链的上一层继承this的,所以它取的是fn1里的this,而fn1是由obj调用的,所以this指向的就是obj。

2.3.3 解决方案二

javascript 复制代码
// 解决方案二:使用闭包
var name = 'window'
var obj = {
    name: 'obj',
    fn1: function() {
    var that = this 
    setTimeout(function() {
          console.log(that.name)
      },0)
    }
}
obj.fn1() // obj 

在fn1里将this赋值给了that,然后在setTimeout函数的回调里使用了that,使得能正确地取到obj的值。这个乍一看有点神奇,但是慢慢剖析就会明白原理其实很简单。我们从作用域、作用域链、执行上下文、执行上下文栈、变量对象、活动对象全了解可以知道fn1的作用域在定义这个函数的时候已经确定,那么该作用域里that这个变量的值也就随之确定了(也就是this),然后setTimeout函数在调用的时候使用了that,这样一来,我们就能正确取到obj里的值了。

2.3.4 解决方案三

javascript 复制代码
// 解决方案三:使用bind/apply/call
var name = 'window'
var obj = {
    name: 'obj',
    fn1: function() {
    setTimeout(function() {
          console.log(this.name)
      }.bind(obj ),0)
    }
}
obj.fn1() // obj 

这一个是最简单的我们最好理解的方式了,它显式地指定this指向了obj,那问题自然很轻松地解决了。

2.4 作为构造函数调用

javascript 复制代码
var name = 'window'
function Person(name) {
    this.name = name ;
 }
var p = new Person('obj')
console.log(p.name) // obj

当使用new关键字的时候this会被绑定在正在构造的新对象。当使用new关键字的时候this会被绑定在正在构造的新对象。

基于上面的了解,我把他们整理成了这一张图:

相关推荐
Nymph_Zhu14 分钟前
pdf转换markdown预览及内容互相点击定位
前端·pdf·vue3·markdown·element-plus
计算机魔术师18 分钟前
Google 一天蒸发5000亿,Reddit 靠 AI 训练喂得饱自己却饿死
前端
小大宇25 分钟前
Vue知识点-ElementPlus-05 输入框
前端·javascript·vue.js
外贸GEO优化38 分钟前
外贸独立站的可抓取性:JS 渲染、懒加载与无限滚动到底影响什么
开发语言·javascript·ecmascript
l1m0_1 小时前
AI设计工具有哪些?Paico、Pixso AI、墨刀AI、Lovable、Codex怎么选
前端·人工智能·ai·设计·墨刀·codex·pixso
web打印社区1 小时前
Lodop在Edge和双核浏览器-先分清内核
前端·javascript·edge·pdf·ecmascript·html5
系统集成-鹰翔1 小时前
ERP对接升级提示数据库迁移失败:SQLite逐版本事务到底回滚到哪一步
javascript·数据库·经验分享·后端
西瓜拿铁好喝1 小时前
开源和闭源 AI 办公工具,分别适合谁
java·前端·数据库
IT_陈寒1 小时前
深入理解SpringBoot:核心原理与最佳实践
前端·人工智能·后端
风骏时光牛马1 小时前
大模型综合能力多维评测:性能、逻辑与落地表现对比
前端