理解掌握JavaScript的this的指向

彻底理解Javascript中的THIS JS中THIS的五种情况 事件绑定 普通函数执行 构造函数执行 箭头函数 call/apply/bind THIS:全局上下文中的THIS是WINDOW;块级上下文中没有自己的THIS,它的THIS是继承所在上下文中的THIS的;在函数的私有上下文中,THIS的情况会多种多样,也是接下来我们重点研究的; THIS不是执行上下文(EC才是执行上下文),THIS是执行主体 例如:Tom拿着鸡蛋灌饼去公司吃早餐(事情本身是吃早餐,Tom吃早餐,这件事情的主体是Tom【THIS】,在公司吃,公司是事情发生所在的 阅读详情

学了JavaScript将近一年了,对于this的掌握却还是不太熟悉,甚至有时候都不知道它到底指向哪里,在看了《你不知道的JavaScript上》中关于this的指向的解析,对this的指向认识清晰了不少,接着又在网上查阅了一些资料,写下这篇博客来分享我对this的指向的理解。如果有什么不对请各位大佬指出我的错误。

在此之前我对this的理解是函数作用域中指向该函数,在对象中使用就指向该对象,但实际上,this真正的指向需要知道它所使用的位置,即它的调用位置。下面介绍this的四条绑定规则。(这四条规则的优先级是默认绑定<隐式绑定<显示绑定<new绑定,这里就不做优先级比较,下面介绍完后各位可以尝试优先级是否如上所说)

默认绑定


默认绑定在平时的使用中非常常见,我的理解是this的调用的位置在全局运行环境中,而全局环境下的this会指向全局对象(在使用Web Worker加载的文件中,this指向Web Worker对象),如下面这段代码。

function fn(){
    var a=1;
    console.log(this.a);
}
var a=2;
fn()
// 2

上面这行代码,可能会让人误以为会打印出1,但实际上却是打印出了2。这是因为this对象是在全局作用域下调用的,所以实际上调用了全局作用域下的变量a。要注意的是,如果在严格模式下的话,this会指向undefined,所以上面的代码在严格模式中是会报错的。

function fn(){
    'use strict'
    var a=1;
    console.log(this.a);
}
var a=2;
fn()
// VM2278:4 Uncaught TypeError: Cannot read property 'a' of undefined at fn

在判断为不是其他几种绑定形式时,就可以视为是默认绑定了。

隐式绑定


隐式绑定考虑的是调用位置是否有上下文对象,或者是否被某个对象拥有或包含。

(上下文对象包含变量对象,作用域链和this指针,如果调用位置有上下文对象的话,this指向其this指针指向的位置)

隐式绑定主要有下面几种情况,作为对象时的方法,原型链上的调用,getter和setter中的this以及作为一个DOM事件处理函数。

作为对象的方法

var obj={
    a:1,
    fn(){
        console.log(this.a);
    }
}
var a=2;
obj.fn()

// 1

这里要注意的是,最后的结果之所以是1,是因为调用时是对象obj调用了fn方法,并非是因为方法定义在obj对象中,可以用下面的代码来看。

var obj={
    a:1,
    fn(){
        console.log(this.a);
    }
}

var obj1={
    a:3,
    fn:obj.fn
}

obj1.fn();

// 3

在这段代码中可以看到,虽然方法fn定义在对象obj里面,但是是用obj1来调用方法fn的,所以最后this指向的是调用该方法的对象obj1。

如果在使用对象链式调用方法时,方法中的this指向链的最后一个对象。如下代码

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

var obj1 = {
    a: 1,
    fn: fn
}

var obj2 = {
    a: 2,
    obj1: obj1
}

console.log(obj2.obj1.fn());

// 1

可以看到,最后的this是指向对象链最后的obj1。若obj1中没有属性a的话,最后的结果会返回undefined。

原型链上的调用

原型链上的this指向的判断也是一样的,关键在于this是在哪里调用的,看看下面这段代码

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

var obj1 = {
    a: 1,
    fn: fn
}

var obj2 = Object.create(obj1);

obj2.a = 2;

console.log(obj2.fn());

//2

在这段代码中,方法fn虽然定义在对象obj1上,但是调用时是在obj2对象上调用的,所以调用的是obj2对象上的a。而这样实际上和上面的对象的调用是一样的,不一样的地方在于,如果这里的对象obj2没有属性a的话,会沿着原型链寻找属性a,所以下面这段代码最后会打印出1。

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

var obj1 = {
    a: 1,
    fn: fn
}

var obj2 = Object.create(obj1);


console.log(obj2.fn());

// 1

getter和setter中的this

如果将this写在getter和setter的方法中的话,this会指向getter和setter方法所属的对象。

var obj = {
    n: 1,
    get num() {
        return this.n;
    }
}

console.log(obj.num);

// 1

如上面代码,对象obj获取其属性num,调用了其getter方法,所以this指向了对象obj,最后返回了对象obj的属性n的值。setter也是同样的道理。

var obj = {
    n: 1,
    set num(val) {
        this.n = val;
    }
}

console.log(obj.n);
// 1

obj.num = 10;

console.log(obj.n);
// 10

DOM事件处理函数

在DOM事件处理函数上的this对象指向触发该事件的元素。

<body>
    <p id="dom">DOM</p>
</body>
<script>
    var p = document.getElementById('dom');

    function fn() {
        console.log(this.innerHTML);
    }

    p.onclick = fn;
    // DOM
</script>

上面代码中,点击了p标签后就会在控制台打印出DOM,这是因为this指向了p。

 

关于隐式绑定,我的理解是在使用时没有明确指出this指向哪个对象,通过在某个对象上调用函数,将该调用函数中的this指向做出调用这个操作的对象。

而隐式调用在某些情况下会出现隐式丢失的情况,即失去了对对象的绑定。如下代码

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

var obj = {
    a: 1,
    fn: fn
}

var f = obj.fn;

var a = 2;

f();
// 2

这里的f=obj.fn,看起来好像是在obj对象中调用该方法的,但仔细看一下就会发现,这条语句是将该函数fn赋值给变量f,即这里的f实际上严格等于fn,即是在全局环境下调用了fn,所以这其实是默认绑定的情况。setTimeout第一个参数传入函数名时也会出现这种情况。

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

var a = 1;

var obj = {
    a: 2,
    fn: fn
}

setTimeout(obj.fn, 100)
// 1
//等同于
setTimeout(function fn(){
    console.log(this.a);
},100)

显式绑定


显式绑定,顾名思义就是显式地将绑定写出来,与隐式绑定不同,显式绑定会明确地将要绑定的对象写出来。显式绑定主要和call(),apply()和bind()三个方法密切相关,而事实上这三个方法的第一个参数就是要来绑定this对象的。

不考虑其后面的参数,这三个方法在this绑定上是一样的,我们就call方法来进行解析。

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

var obj = {
    a: 1
}

var a = 2;

fn.call(obj);

// 2

如上代码,使用call方法显式地将this对象指向对象obj,所以最后打印出的是obj对象的属性a的值。像这种绑定的方式称为硬绑定,硬绑定的缺点在于会降低函数的灵活性,要绑定的对象必须显式地写出来,而且使用硬绑定之后就没法再使用隐式绑定和硬绑定来修改this对象的指向了。

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

var obj = {
    a: 1
}

var a = 2;

var obj1 = {
    a: 3,
    fn: fn.call(obj)
}

obj1.fn;// 尝试使用obj1隐式绑定

// 1  还是原来的硬绑定

function fn1() {
    fn.call(obj);
}

fn1.call(window);// 尝试使重用硬绑定绑定到全局

// 1  还是原来的硬绑定

对于这些硬绑定的缺点,JavaScript有软绑定来解决这些问题,下面用《你不知道的JavaScript上》里面的部分代码来解析

下面是软绑定softBind()的方法

if (!Function.prototype.softBind) {
    Function.prototype.softBind = function(obj) {
        var fn = this;
        var curried= Array.prototype.slice.call(arguments, 1);//获取绑定对象外的参数
        var bound = function() {
            return fn.apply(
                (!this || this === (window || global)) ?obj : this, 
                //检查是否为undefined或者全局对象(默认绑定),是则将默认对象obj绑定到this,否则不修改this
                curried.concat.apply(curried, arguments)
            );
        };
        bound.prototype = Object.create(fn.prototype);
        return bound;
    };
}

软绑定关键在于若调用this时绑定到全局或者undefined(默认绑定),则将其绑定到之前传入的默认绑定对象,若不是默认绑定的情况,则不修改this,即使this绑定到新的对象上。

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

var obj1 = { name: "obj1" },
    obj2 = { name: "obj2" },
    obj3 = { name: "obj3" };

var fooOBJ = foo.softBind(obj1);
fooOBJ();// obj1 使用软绑定绑定,因为当前this为默认绑定的情况,所以this指向了传入的对象obj1

obj2.foo = foo.softBind(obj1);
obj2.foo();// obj2  使用隐式绑定成功修改this绑定的对象

fooOBJ.call(obj3);// obj3  使用硬绑定成功修改this绑定的对象

setTimeout(obj2.foo, 1000);// obj1  与上面的fooOBJ()一样,这里等同于默认绑定的情况,所以this指向了传入的对象obj1

new绑定


new绑定出现在使用new操作符构造对象的时候,它会将函数中的this指向构建的新对象。

function fn(val) {
    this.a = val;
}

var obj = new fn(1);

console.log(obj.a);

上面代码中,方法fn将传入的参数作为this指向的对象的属性a的值,而通过new运算符的构建,使this对象指向obj,所以obj的属性a被传入值1。

 

判断this指向


综上所述,绑定this的指向就分为以下几步

1.判断是否是new运算符创建的,如果是的话则指向新创建的对象

2.判断是否是显式绑定的(apply,call,bind或其他API调用的“上下文”),如果是则指向指定的对象

3.判断是否为隐式绑定的(在某个上下文对象中调用),如果是则指向该上下文对象

4.如果以上情况都不是的话,则为默认绑定,严格模式下指向undefined,非严格模式下指向全局

除了上面这几步外,还有例外情况,即ES6中的箭头函数,箭头函数比起普通函数更容易写,但存在的问题是箭头函数内的this会由外部的作用域来决定。

function fn() {
    return (a) => {
        console.log(this.a);// this继承自fn的this
    }
}

var obj1 = {
    a: 1
}

var obj2 = {
    a: 2
}

var o = fn.call(obj1);
o.call(obj2);
// 1

上面代码中,fn返回的箭头函数中的this实际上继承自fn中的this,所以在后面的代码中,fn绑定obj1,返回的箭头函数绑定obj2,最后打印出的是1,就是因为实际上指向的是fn绑定的对象。

 

以上即为我对JavaScript的this对象指向的理解,希望对大家有所帮助,也希望有大佬能指出我的不足。

MobaXterm结合SSH密钥对安全连接阿里云ECS的实战教程 本文详细介绍了如何使用MobaXterm结合SSH密钥对安全连接阿里云ECS的实战教程。通过对比传统密码登录的风险,重点讲解了密钥对的生成与配置、阿里云控制台的密钥绑定技巧,以及MobaXterm的高级设置和故障排查方法,帮助用户实现高效、安全的远程连接。 阅读详情

相关推荐

揭秘大型语言模型:从神经元到思维透明的奇妙旅程

这篇博客带你走进大型语言模型的内部世界,从神经元的小任务,到功能向量的团队合作,再到层间的协作和思维的透明化。掌握这些知识,能让你在开发中更高效地优化AI,在研究中更深入地探索模型的奥秘。建议多动手实践,把这些理论变成自己的能力!

数据与算法架构提升之路专栏 1520

this指向详解

this指向详解 六月第一篇文章,也是我第一次接触思维脑图,并尝试将它运用到平时的学习中,我们共勉! 思考 + 导图 + 示例代码 => 船新版本 目录 前言+思考题 一、this的指向 二、call和apply 三、模拟实现一个call 四、bind 五、结尾 前言+思考题 记得当时找实习的时候,总是会在简历上加上一句——熟悉Js,例如this指向、call、apply等… 而每次投递简历时我都会经历如下步骤 面试前,去问度娘——this指向可以分为哪几种啊~、call和apply的区别是什么

liyongchunscr的博客 965

HarmonyOS逆向降级实战:从鸿蒙2.0回退至EMUI 10.1的完整路径解析

本文详细解析了从HarmonyOS 2.0逆向降级至EMUI 10.1的完整操作流程,涵盖必备工具准备、数据备份策略及阶梯式降级步骤。针对华为手机用户遇到的兼容性问题,提供HiSuite和HiSuite Proxy工具的具体使用方法,并分享降级失败应急处理与系统优化技巧,帮助用户安全高效完成系统回退。

weixin_27741699的博客 1895

obj.fn()

想了很久 let obj = { fn: function(){ console.log('fn()'); } } console.log(obj.fn()); 结果: fn() 函数默认返回undefined return undefined 给fn函数返回一个字符串 let obj = { fn: function(){ console.log('fn()');

yrfjygb的博客 503

Ubuntu20.04下Intel AX201网卡驱动安装全攻略:从内核升级到固件更新

本文详细介绍了在Ubuntu 20.04系统上解决Intel AX201无线网卡驱动问题的完整方案。针对戴尔游匣G15等新硬件,通过升级内核至HWE版本、从官方仓库获取最新固件文件,并调整BIOS设置,彻底解决Wi-Fi无法识别或连接不稳定的问题,为开发者提供了一套从诊断到修复的实践指南。

gpt4scribbler的博客 690

避开这些坑!海天MA1600注塑机数据采集项目经验分享

本文分享了海天MA1600注塑机数据采集项目的实战经验。针对KEBA控制器接口不开放的难题,项目采用专用网关进行协议转换,并详细剖析了网络部署、ModbusTCP配置、数据准确性保障及现场运维中遇到的典型陷阱与解决方案,为同类工业物联网项目提供宝贵参考。

o4p5q6r7s的博客 491

call,bind,apply绑定this

call、apply、bind方法绑定this

有点打脑壳的博客 1214

S32K系列之PDB框图详解及PDB触发ADC

可编程延迟模块PDB,PDB可提供从内部或外部触发或可编程间隔信号到ADC硬件触发输入的可控制延迟。 PDB可以选择提供脉冲输出,用作CMP块中的采样窗口。 S32K系列的PDB资源如下表: PDB功能框图 在下图中,以下字母表示的意义: N:PDB通道的总数 n:PDB通道号,范围从0到N-1 M:每个PDB通道的总可用预触发 m:预触发编号,范围从0到M-1 Y:脉冲输出的总数 y:脉冲数...

zz56z56的博客 1万+

layui table layui open

html页面 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>table</title> <link rel="stylesheet" href="https://www.layuicdn.com/layui/css/layui.css" media="all"> </head> <body>

KingCruel的专栏 590

FM收音机调试-RDA5807M

收音机调试 IC型号:RDA5807M

mangofu的博客 6164

【Zephyr电源与功耗专题】13_PMU电源驱动介绍

本文介绍的PMU芯片包含2路DCDC和6路LDO,在Zephyr实时操作系统下实现了完整的电源管理解决方案。

zero的博客 842

理解js中this的指向

转载自彻底理解js中this的指向,不必硬背。

Wind_waving的博客 128

MicroChip的SmartFusion2的M2S090芯片的全流程开发环境搭建和Demo设计

MicroChip的SmartFusion2的M2S090芯片的全流程开发环境搭建和Demo设计

qq_45806640的博客 455

彻底理解js中this的指向

https://www.cnblogs.com/pssp/p/5216085.html

aliven1的博客 320

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

JS的this指向理解

参考: http://www.ruanyifeng.com/blog/2018/06/javascript-this.html 1、为什么函数内部要设置this? var obj = { foo: function () { console.log(this.bar) }, bar: 1 }; var foo = obj.foo; var bar = 2; obj.foo() // 1 foo() // 2 this指的是函数运行时所在的环境,那么函数的运行环境到底是怎么决定的?为什么ob.

qq_42063793的博客 265

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

js中this的指向(彻底理解js中this的指向,不必硬背)

首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然网上大部分的文章都是这样说的,虽然在很多情况下那样去理解不会出什么问题,但是实际上那样理解是不准确的,所以在你理解this的时候会有种琢磨不透的感觉),那么接下来我会深入的探讨这个问题例子1: 按照我们上面说的this最终指向的是调用它的对象,这里的函数a实际是被Window对象所点出来的,下面的代码就可以

qq_60060362的博客 1012

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

彻底理解js中this的指向,不必硬背

转:https://www.cnblogs.com/pssp/p/5216085.html 首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然网上大部分的文章都是这样说的,虽然在很多情况下那样去理解不会出什么问题,但是实际上那样理解是不准确的,所...

maquealone的博客 259

深入理解 JavaScript 中的 this 指向

正值春招火热招聘阶段,我近期在复习JavaScript的相关知识点,其中“this”知识点是前端面试中高频面试内容,因此整理和总结一篇相关知识点文章和大家分享!this全局环境:非严格模式下指向全局对象,严格模式下指向undefined。构造函数:使用new时,this指向新创建的对象。显式绑定:通过callapplybind可以显式改变this的指向。上下文对象:通过对象调用函数时,this指向该对象。箭头函数this指向外层作用域。

科技改变世界,技术驱动未来。 1171

深入理解JavaScript中this的指向及应用场景

this的指向在JavaScript中是一个复杂但又非常重要的概念。它的指向会根据函数的调用方式、是否处于严格模式、是否作为对象方法或构造函数等多种因素而变化。在实际开发中,需要仔细分析函数的调用场景,并且可以利用callapply和bind方法来灵活地控制this的指向,以满足代码的逻辑需求。同时,深入理解this的指向对于阅读和理解他人代码以及编写高效、可维护的JavaScript代码都具有重要的意义。

你若盛开,清风自来 963

彻底理解js中this的指向,不必硬背。

原文地址:https://www.cnblogs.com/pssp/p/5216085.html

每天多一点干货 543

彻底理解JavaScript中this的指向

在网上,大部分文章都会出现下面这段话:this的指向在函数定义的时候是确定不了的,只有在函数执行的时候才能确定this到底指向谁,实际上this最终指向的是那个调用他的对象这句话总是让人有哦一种琢磨不透的感觉。为什么要理解this?如果已经学过了面向对象,那么就应该指导this的重要性!1.我们来看一个例子:function fun(){ var userName = "lzh"; ...

weixin_41646391的博客 756

关于 JavaScript 中 this 指向的理解

文章目录1. 默认绑定规则2. 隐式绑定规则3. 显示绑定:call,apply,bind4. new 绑定 我们在写前端页面的时候,编写JavaScript代码的时候经常会用到this关键字,比如绑定事件等等,但是JavaScript中的this指向问题一直都是比较让人头疼的问题,特别是对于初学者来讲,本来认为代码没有什么问题,结果运行出来不尽人意,而且还要花大量时间来调试找到问题所在。以下内容是根据自己所理解进行分享,有什么不对的地方希望大家指出,并一起讨论,一起进步。 首先我们要明白,this 是

Mr_changxin的博客 881

js中的this指向理解

1:为什么要使用this? this提供了一种更优雅的方法来隐式'传递'一个对象的引用,因此可以将API设计得更加简洁并且易于复用。 需要注意大家一般会有的两个误解: (1)this指向函数自身 (2)this指向函数的作用域 作用域无法通过JavaScript代码访问,它存在于JavaScript引擎内部。每当把this和词法作用域的查找混合使用时,一定要提醒自己,这是无法实现的!...

liujiujiang的博客 353
上一篇: ES6学习笔记(十七)类class
下一篇: JavaScript辨别apply,call,bind 用法与性能
前端小黑
博客等级 码龄9年 148粉丝 222原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值